백준 - 주사위 굴리기 (14499)

아놀드·2021년 7월 26일
0

백준

목록 보기
5/73
post-thumbnail

1. 문제

문제 링크


2. 풀이

2-1. 조건

  1. 가장 처음에 주사위에는 모든 면에 0이 적혀져 있다.
  2. 주사위는 지도 위에 윗 면이 1이고, 동쪽을 바라보는 방향이 3인 상태로 놓여져있다.
  3. 주사위를 굴렸을 때, 이동한 칸에 쓰여 있는 수가 0이면, 주사위의 바닥면에 쓰여 있는 수가 칸에 복사된다. 0이 아닌 경우에는 칸에 쓰여 있는 수가 주사위의 바닥면으로 복사되며, 칸에 쓰여 있는 수는 0이 된다.

2-2. 풀이

처음 이 문제를 접할 땐 막막한 느낌일 겁니다.
정육면체의 주사위를 어떻게 구현하고 그 주사위를 굴렸을 때마다
조건에 충족하도록 주사위와 지도에 숫자를 입력했다 지워줘야 하며
맨 윗면의 숫자를 출력해 줘야 하죠.
이런 식으로 생각하고 구현했다가는 코드가 난잡하고 버그도 난무할 겁니다.

그렇다면 어떻게 접근해야 할까요?
우리는 현실 세계의 복잡한 문제를 컴퓨터가 이해할 수 있도록
최대한 단순하고 쉽게 생각해야 합니다.
그렇다면 주사위를 단순한 1차원 배열로 생각해보는 건 어떨까요?

사실 문제에서 힌트를 많이 줬습니다.

주사위 전개도를 그려줬고 윗면은 숫자1, 아랫면은 숫자6으로 고정이 되어있죠.
이런 아이디어를 바탕으로 주사위가 동서남북으로 굴러갈 때마다
전개도를 갱신하는 식으로 생각해봅시다.

동쪽으로 굴러갈 때는

     2			   2
    413         ->        641
     5			   5
     6			   3
  
  

전개도는 이렇게 갱신이 됩니다.
아랫면(6)이 왼쪽면(4)으로 이동
윗면(1)이 오른쪽면(3)으로 이동
오른쪽면(3)이 아랫면(6)으로 이동
왼쪽면(4)이 윗면(1)으로 이동

서쪽으로 굴러갈 때는 반대로 하면 됩니다.

북쪽으로 굴러갈 때는

  2                6
 413        ->    423
  5                1
  6		   5

전개도는 이렇게 갱신됩니다.
윗면(1)이 중간면(5)으로 이동
중간면(2)이 윗면(1)으로 이동
아랫면(6)이 중간면(2)으로 이동
중간면(5)이 아랫면(6)으로 이동

남쪽으로 굴러갈 때는 반대로 하면 됩니다.

주사위를 굴리는 로직을 생각했으니 남은 일은
1차원 배열에 주사위를 담고
주사위가 이동할 때마다 주사위를 갱신해주며
주사위 배열의 첫번째 인덱스(주사위의 윗면)을 출력하면 됩니다.

총 정리를 하면
1. 주사위를 표현할 1차원 배열을 선언
2. 주사위를 굴릴 때마다 인덱스들을 갱신
3. 다음 이동할 지도 위치가 0이면 주사위 배열의 6번째 인덱스(아랫면) 대입,
0이 아니면 주사위 배열의 6번째 인덱스(아랫면)에 지도 위치의 숫자 대입 후, 지도 위치의 숫자 0으로 초기화
4. 1번째 인덱스(윗면) 출력

3. 전체 코드

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Main {

	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N, M, x, y, K;
	static int[] mx = {0, 0, -1, 1}, my = {1, -1, 0, 0};
	static int[][]  A; // 지도
	static int[] dice = new int[7]; // 1. 주사위를 표현할 1차원 배열
	
	public static void main(String[] args) throws Exception {
		String[] s = br.readLine().split(" ");
		N = Integer.parseInt(s[0]);
		M = Integer.parseInt(s[1]);
		x = Integer.parseInt(s[2]);
		y = Integer.parseInt(s[3]);
		K = Integer.parseInt(s[4]);
		
		A = new int[N][M];
		
		for (int i = 0; i < N; i++) {
			s = br.readLine().split(" ");
			for (int j = 0; j < M; j++)
				A[i][j] = Integer.parseInt(s[j]);
		}
		
		s = br.readLine().split(" ");
		
		for (int i = 0; i < K; i++) {
			int dir = Integer.parseInt(s[i]) - 1;
			
			int nx = x + mx[dir], ny = y + my[dir];
			
			// 범위를 벗어난 경우
			if (nx < 0 || nx >= N || ny < 0 || ny >= M) continue;
			
			int[] tmp = dice.clone();
			
			// 2. 주사위를 굴릴 때마다 인덱스들을 갱신
			switch (dir) {
			// 동
			case 0:
				dice[1] = tmp[4];
				dice[6] = tmp[3];
				dice[4] = tmp[6];
				dice[3] = tmp[1];
				break;
			// 서
			case 1:
				dice[4] = tmp[1];
				dice[3] = tmp[6];
				dice[6] = tmp[4];
				dice[1] = tmp[3];
				break;
			// 북
			case 2:
				dice[5] = tmp[1];
				dice[1] = tmp[2];
				dice[2] = tmp[6];
				dice[6] = tmp[5];
				break;
			// 남
			case 3:
				dice[1] = tmp[5];
				dice[2] = tmp[1];
				dice[6] = tmp[2];
				dice[5] = tmp[6];
				break;
			}
			
			// 3. 지도가 0이면 아랫면의 숫자 대입, 
			if (A[nx][ny] == 0) {
				A[nx][ny] = dice[6];
			} 
			// 지도가 0이 아니면 지도에 아랫면의 숫자 대입 후, 지도 0으로 초기화
			else {
				dice[6] = A[nx][ny];
				A[nx][ny] = 0;
			}
			
			x = nx;
			y = ny;
			
			// 4. 지도 출력
			bw.write(dice[1] + "\n");
		}
		
		bw.close();
	}
}
profile
함수형 프로그래밍, 자바스크립트에 관심이 많습니다.

0개의 댓글