입력으로 보드의 크기, 사과의 위치, 뱀의 방향 변환 정보를 받아 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에서 마지막 위치를 제거한다.
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;
}
}