Post

Baekjoon 3190 뱀

문제 이해

단순한 뱀 게임을 구현하는 문제이다.

  • 뱀은 1초에 한 칸 씩 앞으로 이동한다.
  • 사과를 먹으면 꼬리가 한 칸 길어진다.
  • 벽에 머리를 박거나 꼬리에 머리를 박으면 게임 오버!

입력으로 맵의 크기와 사과의 위치와 몇 초에 방향 전환이 이루어지는지 주어진다.

입출력 조건 확인

시간 복잡도를 아직 어떻게 계산하는지 정확히 모름…

맵의 크기도 100이 최대이고 방향 전환도 10,000 이하에서 이루어지고 반복문 하나로 해결할 계획이니 상관 없지 않을까?

문제 풀이 내용 정리

  1. 맵의 크기를 입력 받으면 2중 배열로 맵(벽: -1, 빈 공간: 0)을 그린다.
  2. 사과의 위치를 입력 받으면 맵에 사과의 위치(2)를 찍는다.
  3. 방향 전환 시간과 방향을 입력받고 반복문에 진입한다.

반복문에서는 뱀이 한 칸 씩 이동하고, 방향 전환이 일어나는 시각이 되면 방향을 전환한다.

뱀의 위치는 큐에 들어가 있어서 매 초 마다 진행 방향의 좌표를 큐에 넣고, 좌표 하나를 빼는 작업을 반복한다.

만약 진행 방향에 사과가 있다면 먹고 해당 초에는 큐에서 좌표를 빼지 않는다.

만약 진행 방향에 벽이나 꼬리가 있다면 반복문을 종료한다.

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.awt.Point;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int mapSize = sc.nextInt();
        int[][] map = new int[mapSize + 2][mapSize + 2];
        Queue<Point> snake = new LinkedList<Point>();
        snake.offer(new Point(1, 1));
        int time = -1;

        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map.length; j++) {
                if (i == 0 || j == 0 || i == mapSize + 1 || j == mapSize + 1) {
                    map[i][j] = -1;
                } else {
                    map[i][j] = 0;
                }
            }
        }

        int apple = sc.nextInt();
        sc.nextLine();
        for (int i = 0; i < apple; i++) {
            String[] tmp = sc.nextLine().split(" ");
            map[Integer.parseInt(tmp[0])][Integer.parseInt(tmp[1])] = 2;
        }

        Queue<String[]> turn = new LinkedList<>();

        int[] goX = {0, -1, 0, 1};
        int[] goY = {1, 0, -1, 0};
        int head = 0;
        int nextX = 0;
        int nextY = 0;
        Point headFront = new Point(1, 1);
        int turnCount = sc.nextInt();
        sc.nextLine();
        for (int i = 0; i < turnCount; i++) {
            turn.offer(sc.nextLine().split(" "));
        }
        map[headFront.x][headFront.y] = 1;

        while(true) {
            time++;

            if (turn.isEmpty()) {}
            else if (Integer.parseInt(turn.peek()[0]) == time) {
                if (turn.peek()[1].equals("D")) {
                    head = head - 1;
                    if (head < 0) head += 4;
                } else {
                    head = head + 1;
                    if (head > 3) head -= 4;
                }
                turn.poll();
            }

            nextX = headFront.x + goX[head];
            nextY = headFront.y + goY[head];

            snake.offer(new Point(nextX, nextY));
            headFront = new Point(nextX, nextY);

            if (map[nextX][nextY] == 2) {
            } else if (map[nextX][nextY] == -1) {
                time++;
                break;
            } else if (map[nextX][nextY] == 1) {
                time++;
                break;
            } else {
                Point tmp = snake.poll();
                map[tmp.x][tmp.y] = 0;
            }

            map[nextX][nextY] = 1;
        }

        System.out.println(time);
    }
}

코드 문제점 및 해결 방법

왼쪽과 오른쪽의 방향 전환을 이런 방식으로 하는 게 맞는지 모르겠다.

분명 더 좋은 방법이 있을 것 같은데 시간이 없어서 그냥 생각나는 대로 구현했다.

그리고 코드가 너무 지저분하다. 선언이랑 이런 것들을 기능마다 모아야 할지 아니면 C 스타일로 위에 쭉 선언하고 작성할지 고민해봐야 할 것 같다.

벽이나 꼬리에 박으면 종료되는 조건문에서 time을 하나씩 늘려주는데, 이렇게 안하면 정답이 안나와서 그대로 넣기는 했지만 더 깔끔한 방법이 있을 것 같아서 나중에 생각나면 고쳐봐야 할 것 같다.

This post is licensed under CC BY 4.0 by the author.