[ 백준 ] 3190 뱀

codesver·2023년 7월 5일
0

Baekjoon

목록 보기
32/72
post-thumbnail

📌 Problem

N x N 크기의 보드판에는 K개의 사과들이 존재한다. 1의 길이를 시작으로 좌측상단에서 오른쪽 방향으로 출발한 뱀은 매초 1칸씩 움직인다. 만약 움직인 칸에 사과가 있다면 사과를 먹고 길이가 1 늘어난다. 즉, 꼬리는 움직이지 않는다. 특정 시간에는 머리의 방향을 돌리는데 L은 왼쪽 D는 오른쪽이며 해당 시간에 움직임을 끝낸 후 방향을 돌린다. 뱀이 벽이나 자신에게 부딪혔을 때의 게임 시간을 구한다.

  1. N X N의 보드에서 좌측상단에서 1의 길이로 오른쪽을 바라본 상태로 시작한다.
  2. 1초 동안 움직인다.
    2-1. 머리를 바라보는 방향으로 1칸 움직인다.
    2-2. 벽이나 자신에게 부딪히면 게임을 종료한다.
    2-3. 사과를 먹지 못했으면 꼬리도 1칸 움직인다.
  3. 해당 게임 시간에 회전 동작이 있으면 회전한다.
    3-1. 회전 방향이 L이면 머리를 왼쪽으로 90도 회전시킨다.
    3-2. 회전 방향이 D이면 머리를 오른쪽으로 90도 회전시킨다.

📌 Code

int N = Integer.parseInt(reader.readLine()); // Input : Size of board
int K = Integer.parseInt(reader.readLine()); // Input : Number of apple

Dummy dummy = new Dummy(N); // Dummy Game

// Input : Add apples to the game board
StringTokenizer tokenizer;
while (K-- > 0) {
    tokenizer = new StringTokenizer(reader.readLine());
    dummy.addApple(
            Integer.parseInt(tokenizer.nextToken()) - 1,
            Integer.parseInt(tokenizer.nextToken()) - 1
    );
}

// Input : Add turning actions to the game
int turnNum = Integer.parseInt(reader.readLine());
while (turnNum-- > 0) {
    tokenizer = new StringTokenizer(reader.readLine());
    dummy.addTurn(
            Integer.parseInt(tokenizer.nextToken()),
            tokenizer.nextToken().charAt(0)
    );
}

// Output : Time when game ended
result.append(dummy.playGame());

class Dummy {

    private final int[][] moves = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // Moves

    private int headRow, headCol, tailRow, tailCol; // Location of head and tail
    private final int[][] board; // -1 : Apple / 1, 2, 3, 4 : Snake with direction
    private final Queue<Turn> turns = new LinkedList<>(); // Turning actions with time

    public Dummy(int boardSize) {
        board = new int[boardSize][boardSize];
        board[0][0] = 2;
    }

    /**
     * Add apple
     * @param row Row location of apple
     * @param col Column location of apple
     */
    public void addApple(int row, int col) {
        board[row][col] = -1;
    }

    /**
     * Add turning action
     * @param time Turning time
     * @param dir Turning direction
     */
    public void addTurn(int time, char dir) {
        turns.offer(new Turn(time, dir));
    }

    /**
     * Play game until game ends
     * @return Time when game ends
     */
    public int playGame() {
        int time = 0;
        while (true) {
            try {
                time++;
                move();
                turn(time);
            } catch (ArrayIndexOutOfBoundsException e) { // Game ends
                return time;
            }
        }
    }

    /**
     * Move snake
     */
    private void move() {
        // Move head
        int nextRow = headRow + moves[board[headRow][headCol] - 1][0];
        int nextCol = headCol + moves[board[headRow][headCol] - 1][1];

        // Crashes to itself
        if (board[nextRow][nextCol] > 0) throw new ArrayIndexOutOfBoundsException();

        boolean grow = board[nextRow][nextCol] == -1;
        board[nextRow][nextCol] = board[headRow][headCol];
        headRow = nextRow;
        headCol = nextCol;

        // Move tail if didn't grow
        if (!grow) {
            nextRow = tailRow + moves[board[tailRow][tailCol] - 1][0];
            nextCol = tailCol + moves[board[tailRow][tailCol] - 1][1];
            board[tailRow][tailCol] = 0;
            tailRow = nextRow;
            tailCol = nextCol;
        }
    }

    /**
     * Turn head's direction
     * @param time Time of game
     */
    private void turn(int time) {
        if (!turns.isEmpty() && turns.peek().time == time) {
            Turn turn = turns.poll();
            board[headRow][headCol] = ((board[headRow][headCol] - 1)
                    + (turn.dir == 'L' ? 3 : 1)) % 4 + 1;
        }
    }
}

class Turn {
    int time;
    char dir;

    public Turn(int time, char dir) {
        this.time = time;
        this.dir = dir;
    }
}
profile
Hello, Devs!

0개의 댓글