[백준] 3190 뱀 (JAVA)

2025. 10. 30. 15:12·코딩 테스트

문제 링크:

3190번: 뱀

 

 

난이도: 골드 4

 

 

문제:

'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다.

게임은 NxN 정사각 보드위에서 진행되고, 몇몇 칸에는 사과가 놓여져 있다. 보드의 상하좌우 끝에 벽이 있다. 게임이 시작할때 뱀은 맨위 맨좌측에 위치하고 뱀의 길이는 1 이다. 뱀은 처음에 오른쪽을 향한다.

뱀은 매 초마다 이동을 하는데 다음과 같은 규칙을 따른다.

  • 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.
  • 만약 벽이나 자기자신의 몸과 부딪히면 게임이 끝난다.
  • 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
  • 만약 이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸길이는 변하지 않는다.

사과의 위치와 뱀의 이동경로가 주어질 때 이 게임이 몇 초에 끝나는지 계산하라.

 

 

입력:

첫째 줄에 보드의 크기 N이 주어진다. (2 ≤ N ≤ 100) 다음 줄에 사과의 개수 K가 주어진다. (0 ≤ K ≤ 100)

 

다음 K개의 줄에는 사과의 위치가 주어지는데, 첫 번째 정수는 행, 두 번째 정수는 열 위치를 의미한다. 사과의 위치는 모두 다르며, 맨 위 맨 좌측 (1행 1열) 에는 사과가 없다.

 

다음 줄에는 뱀의 방향 변환 횟수 L 이 주어진다. (1 ≤ L ≤ 100)

 

다음 L개의 줄에는 뱀의 방향 변환 정보가 주어지는데, 정수 X와 문자 C로 이루어져 있으며. 게임 시작 시간으로부터 X초가 끝난 뒤에 왼쪽(C가 'L') 또는 오른쪽(C가 'D')로 90도 방향을 회전시킨다는 뜻이다. X는 10,000 이하의 양의 정수이며, 방향 전환 정보는 X가 증가하는 순으로 주어진다.

 

 

출력:

첫째 줄에 게임이 몇 초에 끝나는지 출력한다.

 

 

문제 이해:

이 게임은 정사각형 보드의 (1,1) 위치에서 길이 1짜리 뱀이 출발하여,
입력된 방향 전환 정보에 따라 매초 이동하며 게임이 종료될 때까지 걸린 시간을 구하는 시뮬레이션 문제이다.

 

뱀은 매 초마다 한 칸씩 앞으로 나아가며, 이동한 칸에 사과가 있으면 그 사과를 먹고 몸의 길이가 1 증가한다.
반대로 이동한 칸에 사과가 없다면, 뱀은 머리를 한 칸 늘리는 동시에 꼬리 부분이 한 칸 줄어들어 길이는 그대로 유지된다.

 

이동 도중 뱀이 벽에 부딪히거나 자신의 몸에 닿는 순간 게임은 즉시 종료된다.

 

또한, 입력으로 주어지는 방향 전환 정보는
예를 들어 8 D와 같은 형태로, 이는 8초가 지난 직후에 뱀이 오른쪽(Direction Right) 으로 90도 회전한다는 의미이다.
즉, 뱀은 8초 동안 기존 방향으로 이동한 뒤, 8초가 끝나는 시점에 방향을 바꾼 후 다음 초부터 새로운 방향으로 움직인다.

 

결국 이 문제는 “시간이 흐르며 뱀이 어떻게 이동하고 언제 충돌하는지를 그대로 시뮬레이션하여,
게임이 끝나는 시간을 계산하는 것”이 핵심이다.

 

 

구현 방향:

이 문제를 구현하기 위해서는 큐(Queue) 또는 덱(Deque) 을 사용한다.
뱀의 몸통을 이 자료구조에 저장해두고, 이동할 때마다 머리를 추가하고 꼬리를 제거하는 식으로 동작을 표현할 수 있다.
사과를 먹으면 꼬리를 제거하지 않아 길이가 늘어나고, 사과가 없으면 꼬리 부분만 삭제되어 길이가 유지된다.

 

구현 순서는 다음과 같다.

 

  • 초기 세팅
    보드 크기, 사과의 위치, 방향 전환 정보를 입력받고
    덱에 뱀의 시작 좌표 (1,1) 을 넣는다.
  • 게임 시작
    시간을 0초로 두고, 뱀이 이동을 시작한다.
  • 방향 전환
    주어진 시간이 되었을 때 회전 명령에 따라
    뱀의 이동 방향을 왼쪽(L) 또는 오른쪽(D)으로 바꾼다.
  • 이동
    현재 방향으로 머리를 한 칸 이동시키고, 새 좌표를 덱의 맨 뒤에 추가한다.
  • 사과 확인
    이동한 칸에 사과가 있다면 사과를 없애고 꼬리는 그대로 둔다.
    사과가 없다면 덱의 맨 앞(꼬리)을 제거해 길이를 유지한다.
  • 충돌 검사
    이동한 머리 좌표가 벽 밖이거나 이미 뱀의 몸통에 포함되어 있으면 게임을 종료한다.
  • 시간 증가
    위 과정을 반복하면서 1초씩 시간을 증가시키고,
    충돌이 발생하는 순간의 시간을 결과로 출력한다.

 

이를 코드로 그대로 구현하면 다음과 같다.

 

 

정답 코드:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N,L;
    static int appleCount; //사과 개수
    static int [][]map;
    static int[] changeTime; //위치가 변하는 시간
    static char[] changePos; // 변하는 위치
    static Set<List<Integer>> set = new HashSet<>();
    static int result=0;


    public static void game(int x, int y){
        int time=0;
        int changeIdx=0;
        int dir=3;  //현재 가는 방향 (Up: 1, Down: 2, Right: 3, Left: 4)

        Deque<int[]> dq= new ArrayDeque<>();

        set.add(Arrays.asList(x,y));
        dq.add(new int[]{x,y});

        while (true){
            //뱀 머리 가져오기
            int[] arr = dq.getLast();
            int curX=arr[0];
            int curY=arr[1];
            boolean flag=false;

            //위치를 변경할 시간이면 위치 변경
            if(changeIdx<L && time==changeTime[changeIdx] ){
                switch (dir){
                    case 1:
                        if(changePos[changeIdx]=='D') dir=3;
                        if(changePos[changeIdx]=='L') dir=4;
                        break;
                    case 2:
                        if(changePos[changeIdx]=='D') dir=4;
                        if(changePos[changeIdx]=='L') dir=3;
                        break;
                    case 3:
                        if(changePos[changeIdx]=='D') dir=2;
                        if(changePos[changeIdx]=='L') dir=1;
                        break;
                    case 4:
                        if(changePos[changeIdx]=='D') dir=1;
                        if(changePos[changeIdx]=='L') dir=2;
                        break;
                    default:
                }
                changeIdx++;
            }

            //실제 이동
            switch (dir){
                //위
                case 1:
                    //자기 자신과 만나는 경우
                    if(set.contains(Arrays.asList(curX-1,curY))) flag=true;
                    dq.add(new int[]{curX-1,curY});

                    break;
                //아래
                case 2:
                    if(set.contains(Arrays.asList(curX+1,curY)))flag=true;
                    dq.add(new int[]{curX+1,curY});
                    break;
                //우
                case 3:
                    if(set.contains(Arrays.asList(curX,curY+1)))flag=true;
                    dq.add(new int[]{curX,curY+1});
                    break;
                //좌
                case 4:
                    if(set.contains(Arrays.asList(curX,curY-1)))flag=true;
                    dq.add(new int[]{curX,curY-1});
                    break;
                default:
            }


            int[] last = dq.getLast();
            //게임이 끝난 경우
            if(last[0]<0 || last[1]<0 || last[0]>=N  || last[1]>=N ||flag) {
                time++;
                break;
            }

            //사과를 먹지 못한경우 꼬리 제거
            if(map[last[0]][last[1]]==0){
                int[] first = dq.getFirst();
                set.remove(Arrays.asList(first[0], first[1]));
                dq.removeFirst();
                set.add(Arrays.asList(last[0], last[1]));
            }
            else map[last[0]][last[1]]=0;

            time ++;
        }

        result=time;
    }

    public static void main(String[] args) throws IOException {
        //초기 세팅
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        N=Integer.parseInt(br.readLine());
        appleCount=Integer.parseInt(br.readLine());

        map=new int[N][N];

        for(int i=0; i<appleCount; i++){
            StringTokenizer st=new StringTokenizer(br.readLine());
            int x=Integer.parseInt(st.nextToken());
            int y=Integer.parseInt(st.nextToken());
            map[x-1][y-1]=1; //사과 위치 1로 갱신
        }

        L=Integer.parseInt(br.readLine());
        changePos=new char[L];
        changeTime=new int[L];
        for(int i=0; i<L; i++){
            StringTokenizer st=new StringTokenizer(br.readLine());
            changeTime[i]=Integer.parseInt(st.nextToken());
            changePos[i]=st.nextToken().charAt(0);
        }
        //초기 세팅 끝

        //Game Start
        game(0,0);

        //결과 출력
        System.out.println(result);
        }
}

 

 

 

마무리하며:

이 문제를 해결하는 데 약 2시간 10분 정도가 소요되었다. 단순한 시뮬레이션 문제처럼 보이지만, 실제로 구현 과정에서는 생각보다 많은 복잡함이 있었다. 특히 방향 전환 부분이 까다로웠는데, 뱀의 머리가 바라보는 방향에 따라 ‘왼쪽’과 ‘오른쪽’의 의미가 달라지기 때문에, 단순히 좌표를 더하거나 빼는 수준이 아니라 현재 진행 방향에 따른 회전 로직을 세밀하게 나누어 구현해야 했다.

 

또한 머리와 꼬리의 이동 순서를 처리하는 부분에서도 혼란이 있었다. 예제 2번과 3번을 보면, 머리와 꼬리가 동시에 움직이는 것이 아니라 먼저 머리가 이동하고 그다음에 꼬리가 줄어드는 방식으로 진행된다. 이 차이 때문에 충돌 시점을 계산하는 과정이 헷갈렸고, 머리와 몸이 겹치는 시점을 정확히 판정하기 위해 여러 번 디버깅을 거쳐야 했다.

 

결국, 문제의 핵심은 단순한 알고리즘보다 시뮬레이션의 순서를 얼마나 정확히 구현하느냐에 있었다. 작은 순서 차이 하나로 결과가 완전히 달라지기 때문에, 꼼꼼한 구현력이 요구되는 문제였다.

 

감사합니다.

'코딩 테스트' 카테고리의 다른 글

[백준] 톱니바퀴 (2) (JAVA)  (0) 2025.11.20
[백준] 17406 배열 돌리기 4 (JAVA)  (0) 2025.11.19
[백준] 12100 2048 Easy (JAVA)  (0) 2025.10.28
[백준] 14889 스타트와 링크 (JAVA)  (0) 2025.10.24
[백준] 17144 미세먼지 안녕! (JAVA)  (0) 2025.10.23
'코딩 테스트' 카테고리의 다른 글
  • [백준] 톱니바퀴 (2) (JAVA)
  • [백준] 17406 배열 돌리기 4 (JAVA)
  • [백준] 12100 2048 Easy (JAVA)
  • [백준] 14889 스타트와 링크 (JAVA)
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    타임리프
    객체지향
    컬렉션
    Java
    JPA
    SpringDataJpa
    스프링
    dfs
    thymeleaf
    코딩 테스트
    BFS
    스프링 컨테이너
    재귀
    스프링 데이터 JPA
    코딩테스트
    다형성
    쿼리dsl
    쿼리
    최적화
    spring
    LocalDateTime
    fetch join
    mvc
    불변객체
    예외처리
    SOLID
    QueryDSL
    백준
    자바
    예외 처리
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[백준] 3190 뱀 (JAVA)
상단으로

티스토리툴바