Seren dev's blog
article thumbnail
 

3190번: 뱀

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

www.acmicpc.net

풀이

입력으로 보드의 크기, 사과의 위치, 뱀의 방향 변환 정보를 받아 static 변수에 저장한다.

    static int size; //보드 크기
    static boolean[][] apples; //사과가 있는 칸은 true, 없으면 false
    static HashMap<Integer, String> directChange; //뱀의 방향 변환 정보
    
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        size = Integer.parseInt(br.readLine());

        apples = new boolean[size][size];
        int appleNum = Integer.parseInt(br.readLine());
        StringTokenizer st;
        for (int i = 0; i < appleNum; i++) {
            st = new StringTokenizer(br.readLine());
            int row = Integer.parseInt(st.nextToken());
            int col = Integer.parseInt(st.nextToken());
            apples[row - 1][col - 1] = true;
        }

        directChange = new HashMap<>();
        int dirNum = Integer.parseInt(br.readLine());
        for (int i = 0; i < dirNum; i++) {
            st = new StringTokenizer(br.readLine());
            int second = Integer.parseInt(st.nextToken());
            String dir = st.nextToken();
            directChange.put(second, dir);
        }

        playGame();
    }

 

void playGame() : 문제에서 주어진대로 게임을 실행한다.

    public static void playGame() {
        int headRow = 0, headCol = 0; //현재 뱀의 시작 위치
        int dir = 0; //현재 방향 인덱스

        ArrayList<Point> snake = new ArrayList<>(); //뱀이 있는 칸의 위치를 머리부터 순서대로 저장
        snake.add(new Point(0, 0));

        boolean[][] board = new boolean[size][size]; //뱀이 있는 칸의 위치는 true, 없는 곳은 false
        board[headRow][headCol] = true;

        int second = 0; //게임 플레이 시간(초)

        while (true) {
            //뱀이 방향을 변환할 경우
            if (directChange.containsKey(second)) {
                if (directChange.get(second).equals("D")) {
                    dir = (dir + 1) % 4;
                } else if (directChange.get(second).equals("L")) {
                    dir = (dir + 3) % 4;
                }
            }

            //headRow와 headCol에 뱀의 머리가 있을 다음 위치를 저장한다.
            headRow += dRow[dir];
            headCol += dirCol[dir];
            second++;

            //벽 또는 자기 자신의 몸과 부딪히면 게임이 끝난다.
            if (!checkIndex(headRow, headCol) || board[headRow][headCol]) {
                break;
            }

            //이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다
            if (!apples[headRow][headCol]) {
                moveSnake(snake, board);
            }
            //이동한 칸에 사과가 있다면, 사과를 먹는다.
            else {
                apples[headRow][headCol] = false;
            }

            snake.add(0, new Point(headRow, headCol));
            board[headRow][headCol] = true;
        }

        System.out.println(second);
    }
  • 클래스 Point는 행, 열 위치를 저장하는 클래스로 static class로 선언하였다.

처음 문제를 풀었을 때는 23%에서 "틀렸습니다"가 나왔다. 질문 검색 게시판에서 찾아보니 "사과를 먹고나면 사과가 없어져야 한다."고 나와있어 사과가 있는 칸에 도착하면 apples 값을 업데이트해서 사과를 없앴다.

 

boolean checkIndex(int row, int col): 행, 열 위치가 인덱스를 벗어나지 않으면 true, 벗어나면 false를 반환한다.

    static boolean checkIndex(int row, int col) {
        if (row >= 0 && row < size && col >= 0 && col < size)
            return true;
        return false;
    }

 

void moveSnake(ArrayList<Point> snake, boolean[][] board): 뱀의 마지막(꼬리) 위치를 구해서 board값을 업데이트하고, snake에서 마지막 위치를 제거한다.

    static void moveSnake(ArrayList<Point> snake, boolean[][] board) {
        int lastIndex = snake.size() - 1;
        Point lastPoint = snake.get(lastIndex);

        board[lastPoint.row][lastPoint.col] = false;
        snake.remove(lastIndex);
    }

 

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;

public class Main {

    //행과 열의 위치를 저장한다.
    static class Point {
        int row, col;

        public Point(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }
    
    //방향 배열
    static int[] dRow = {0, 1, 0, -1};
    static int[] dirCol = {1, 0, -1, 0};

    static int size; //보드 크기
    static boolean[][] apples; //사과의 위치
    static HashMap<Integer, String> directChange; //뱀의 방향 변환 정보

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        size = Integer.parseInt(br.readLine());

        apples = new boolean[size][size];
        int appleNum = Integer.parseInt(br.readLine());
        StringTokenizer st;
        for (int i = 0; i < appleNum; i++) {
            st = new StringTokenizer(br.readLine());
            int row = Integer.parseInt(st.nextToken());
            int col = Integer.parseInt(st.nextToken());
            apples[row - 1][col - 1] = true;
        }

        directChange = new HashMap<>();
        int dirNum = Integer.parseInt(br.readLine());
        for (int i = 0; i < dirNum; i++) {
            st = new StringTokenizer(br.readLine());
            int second = Integer.parseInt(st.nextToken());
            String dir = st.nextToken();
            directChange.put(second, dir);
        }

        playGame();
    }

    public static void playGame() {
        int headRow = 0, headCol = 0; //현재 뱀의 시작 위치
        int dir = 0; //현재 방향 인덱스

        ArrayList<Point> snake = new ArrayList<>(); //뱀이 있는 칸의 위치를 머리부터 순서대로 저장
        snake.add(new Point(0, 0));

        boolean[][] board = new boolean[size][size]; //뱀이 있는 칸의 위치는 true, 없는 곳은 false
        board[headRow][headCol] = true;

        int second = 0; //게임 플레이 시간(초)

        while (true) {
            //뱀이 방향을 변환할 경우
            if (directChange.containsKey(second)) {
                if (directChange.get(second).equals("D")) {
                    dir = (dir + 1) % 4;
                } else if (directChange.get(second).equals("L")) {
                    dir = (dir + 3) % 4;
                }
            }

            //headRow와 headCol에 뱀의 머리가 있을 다음 위치를 저장한다.
            headRow += dRow[dir];
            headCol += dirCol[dir];
            second++;

            //벽 또는 자기 자신의 몸과 부딪히면 게임이 끝난다.
            if (!checkIndex(headRow, headCol) || board[headRow][headCol]) {
                break;
            }

            //이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다
            if (!apples[headRow][headCol]) {
                moveSnake(snake, board);
            }
            //이동한 칸에 사과가 있다면, 사과를 먹는다.
            else {
                apples[headRow][headCol] = false;
            }

            snake.add(0, new Point(headRow, headCol));
            board[headRow][headCol] = true;
        }

        System.out.println(second);
    }

    static boolean checkIndex(int row, int col) {
        if (row >= 0 && row < size && col >= 0 && col < size)
            return true;
        return false;
    }

    static void moveSnake(ArrayList<Point> snake, boolean[][] board) {
        int lastIndex = snake.size() - 1;
        Point lastPoint = snake.get(lastIndex);

        board[lastPoint.row][lastPoint.col] = false;
        snake.remove(lastIndex);
    }
}

 

수정한 버전


위의 풀이는 뱀이 자기자신의 몸과 부딪히는지 확인하기 위해 boolean[][] board를 선언하여 board에 뱀이 있는 위치를 표시해주었다. 하지만 클래스 Point의 equals()메서드를 오버라이딩하여 snake.contains(new Point(headRow, headCol))를 통해 뱀이 자기자신의 몸과 부딪히는지 확인할 수 있도록 한다. 즉 board 변수를 사용할 필요가 없다.

또한 snake를 Deque(덱)으로 선언하여 offerFirst(), pollLast() 등의 메서드를 사용할 수 있도록 한다. 즉 moveSnake() 메서드를 사용할 필요가 없다.

contains() 메서드는 equals() 메서드를 호출하므로 equals() 메서드만 오버라이딩하면 된다.

수정한 부분

public class Main {

    //행과 열의 위치를 저장한다.
    static class Point {
        int row, col;

        public Point(int row, int col) {
            this.row = row;
            this.col = col;
        }

        @Override
        public boolean equals(Object obj) {
            Point p = (Point)obj;
            return row == p.row && col == p.col;
        }
    }
    ...
    
    public static void playGame() {
        ...
        
        Deque<Point> snake = new LinkedList<>(); //뱀이 있는 칸의 위치를 머리부터 순서대로 저장
        snake.add(new Point(0, 0));

        int second = 0; //게임 플레이 시간(초)

        while (true) {
            ...

            //벽 또는 자기 자신의 몸과 부딪히면 게임이 끝난다.
            if (!checkIndex(headRow, headCol) || snake.contains(new Point(headRow, headCol))) {
                break;
            }

            //이동한 칸에 사과가 있다면, 사과를 먹는다.
            if (apples[headRow][headCol]) {
                apples[headRow][headCol] = false;
            }
            //이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다.
            else {
                snake.pollLast();
            }

            snake.offerFirst(new Point(headRow, headCol));
        }

        System.out.println(second);
    }
    
    ...
}

전체코드

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

public class Main {

    //행과 열의 위치를 저장한다.
    static class Point {
        int row, col;

        public Point(int row, int col) {
            this.row = row;
            this.col = col;
        }

        @Override
        public boolean equals(Object obj) {
            Point p = (Point)obj;
            return row == p.row && col == p.col;
        }

        @Override
        public int hashCode() {
            return Objects.hash(row + col);
        }
    }

    //방향 배열
    static int[] dRow = {0, 1, 0, -1};
    static int[] dirCol = {1, 0, -1, 0};

    static int size; //보드 크기
    static boolean[][] apples; //사과의 위치
    static HashMap<Integer, String> directChange; //뱀의 방향 변환 정보

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        size = Integer.parseInt(br.readLine());

        apples = new boolean[size][size];
        int appleNum = Integer.parseInt(br.readLine());
        StringTokenizer st;
        for (int i = 0; i < appleNum; i++) {
            st = new StringTokenizer(br.readLine());
            int row = Integer.parseInt(st.nextToken());
            int col = Integer.parseInt(st.nextToken());
            apples[row - 1][col - 1] = true;
        }

        directChange = new HashMap<>();
        int dirNum = Integer.parseInt(br.readLine());
        for (int i = 0; i < dirNum; i++) {
            st = new StringTokenizer(br.readLine());
            int second = Integer.parseInt(st.nextToken());
            String dir = st.nextToken();
            directChange.put(second, dir);
        }

        playGame();
    }

    public static void playGame() {
        int headRow = 0, headCol = 0; //현재 뱀의 시작 위치
        int dir = 0; //현재 방향 인덱스

        Deque<Point> snake = new LinkedList<>(); //뱀이 있는 칸의 위치를 머리부터 순서대로 저장
        snake.add(new Point(0, 0));

        int second = 0; //게임 플레이 시간(초)

        while (true) {
            //뱀이 방향을 변환할 경우
            if (directChange.containsKey(second)) {
                if (directChange.get(second).equals("D")) {
                    dir = (dir + 1) % 4;
                } else if (directChange.get(second).equals("L")) {
                    dir = (dir + 3) % 4;
                }
            }

            //headRow와 headCol에 뱀의 머리가 있을 다음 위치를 저장한다.
            headRow += dRow[dir];
            headCol += dirCol[dir];
            second++;

            //벽 또는 자기 자신의 몸과 부딪히면 게임이 끝난다.
            if (!checkIndex(headRow, headCol) || snake.contains(new Point(headRow, headCol))) {
                break;
            }

            //이동한 칸에 사과가 있다면, 사과를 먹는다.
            if (apples[headRow][headCol]) {
                apples[headRow][headCol] = false;
            }
            //이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다
            else {
                snake.pollLast();
            }

            snake.offerFirst(new Point(headRow, headCol));
        }

        System.out.println(second);
    }

    static boolean checkIndex(int row, int col) {
        if (row >= 0 && row < size && col >= 0 && col < size)
            return true;
        return false;
    }
}
728x90
profile

Seren dev's blog

@Seren dev

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!