Algorithm/BOJ

[ BOJ ] 3190 뱀 G5 삼성 기출(JAVA)

_cpdm_ 2021. 9. 2. 22:11
반응형


 

 

3190번: 뱀

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

www.acmicpc.net

문제 이해
- '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가 증가하는 순으로 주어진다.
아이디어
- 시뮬은 하라는 대로 !
- 뱀을 어떤식으로 구현할 지 고민하다가 Deque을 이용했다.
- 머리 방향은 우 0 하 1 좌 2 상 3 으로 지정해주었다. (시작이 오른쪽이라서..)
- 머리 기준 오른쪽은 현방향에서 +1, 왼쪽은 현방향 -1 로 해주었다.
코드
import java.io.*;
import java.util.*;

public class Main {

	static class Order {
		int sec;
		String dir;

		Order(int sec, String dir) {
			this.sec = sec;
			this.dir = dir;
		}
	}

	static int N, map[][];
	static final int blank = 0, apple = 2;
	static Queue<Order> orders = new LinkedList<>();
	static Deque<int[]> snakes = new LinkedList<>();
	static int[][] dir = { { 0, 1, 0, -1 }, { 1, 0, -1, 0 } };

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		N = stoi(br.readLine());
		map = new int[N][N];
		int appleCount = stoi(br.readLine());
		for (int i = 0; i < appleCount; ++i) {// apple 위치를 입력받는다.
			st = new StringTokenizer(br.readLine(), " ");
			map[stoi(st.nextToken()) - 1][stoi(st.nextToken()) - 1] = apple;
		}
		int orderCount = stoi(br.readLine());
		for (int i = 0; i < orderCount; ++i) {
			st = new StringTokenizer(br.readLine(), " ");
			orders.offer(new Order(stoi(st.nextToken()), st.nextToken()));
		}
		System.out.println(process());
	}

	static int process() {
		snakes.offer(new int[] { 0, 0 });// 뱀의 첫 위치.
		int time = 0;// 현재 시간
		int snakeDir = 0;// R 0 D 1 L 2 R 3
		boolean isGameOver = false;
		while (true) { // 게임이 끝날때까지.
			++time; // 시간 카운팅.
			int[] newHead = {snakes.getLast()[0] + dir[0][snakeDir], snakes.getLast()[1] + dir[1][snakeDir]};
			if (!isBoundary(newHead[0], newHead[1]) || isCrashBody(newHead)) {//새로이동할 위치가 벽이면 게임오버.
				isGameOver = true;
				break;
			}
			snakes.offer(newHead); // 괜찮으면 넣어준다.
			// 이동할 위치가 사과가 있는지 없는지 여부.
			if (isApple(snakes.getLast()[0], snakes.getLast()[1])) {
				map[snakes.getLast()[0]][snakes.getLast()[1]] = blank; // 사과를 비운다.
			} else { // 사과가 없으면 꼬리를 자른다.
				snakes.pollFirst();
			}
			// 회전
			if (!orders.isEmpty() && time == orders.peek().sec) { // 명령을 수행할 수 있는 초가 지났다면
				String newDir = orders.poll().dir; // 새로운 방향을 입력받는다.
				snakeDir = newDir.equals("D") ? snakeDir + 1 : snakeDir - 1;
				snakeDir = snakeDir < 0 ? 3 : (snakeDir > 3 ? 0 : snakeDir); // 값 보정
			}
			if (isGameOver) break;
		}
		return time;
	}

	static boolean isCrashBody(int[] head) {
		for(int[] now : snakes) { // 몸통이랑 박으면 true 반환
			if(now[0] == head[0] && now[1]==head[1]) return true;
		}
		return false;
	}
	
	static boolean isBoundary(int x, int y) {
		return 0 <= x && x < N && 0 <= y && y < N;
	}

	static boolean isApple(int x, int y) {
		return map[x][y] == apple;
	}

	static int stoi(String s) {
		return Integer.parseInt(s);
	}
}

 

 

 


 

 

CPDM

 

choppadontbiteme.tistory.com

 

반응형