[백준] 14499: 주사위 굴리기 (Java)

Yoon Uk·2022년 8월 27일
0

알고리즘 - 백준

목록 보기
60/130
post-thumbnail
post-custom-banner

문제

BOJ 14499: 주사위 굴리기 https://www.acmicpc.net/problem/14499

풀이

조건

  • 주사위는 지도 위에 윗 면이 1이고, 동쪽을 바라보는 방향이 3인 상태로 놓여져 있으며, 놓여져 있는 곳의 좌표는 (x, y) 이다.
  • 가장 처음에 주사위에는 모든 면에 0이 적혀져 있다.
  • 주사위를 굴렸을 때, 이동한 칸에 쓰여 있는 수가 0이면, 주사위의 바닥면에 쓰여 있는 수가 칸에 복사된다.
  • 주사위를 굴렸을 때, 0이 아닌 경우에는 칸에 쓰여 있는 수가 주사위의 바닥면으로 복사되며, 칸에 쓰여 있는 수는 0이 된다.
  • 주사위는 지도의 바깥으로 이동시킬 수 없다. 만약 바깥으로 이동시키려고 하는 경우에는 해당 명령을 무시해야 하며, 출력도 하면 안 된다.

풀이 순서

  • 명령에 맞춰 주사위가 위치한 좌표를 구한다.
    • 이 때, 새롭게 구한 위치가 범위를 벗어났다면 continue를 한다.
  • 명령에 맞춰 굴린 주사위의 상태를 구한다.

    예를 들어,

    • 주사위를 동쪽으로 한 번 굴리게 되면
      주사위의 위 쪽 면이전 상태의 서 쪽 면에 있던 면이 오게 된다.
  • 이동한 칸에 적힌 숫자가 0이라면
    • 주사위의 바닥 면에 적힌 숫자를 칸에 복사한다.
  • 이동한 칸에 적힌 숫자가 0이 아니라면
    • 칸에 적힌 숫자를 주사위의 바닥 면에 복사한다.
    • 그 칸의 숫자는 0으로 갱신한다.

코드

import java.util.*;
import java.io.*;

public class Main {
    
	static int N, M, x, y, K;
	static int[][] map;
	
	static int[] dice; // 주사위의 위치에 적힌 값을 기록할 배열 -> 위/동/서/남/북/아래 순으로 기록함
	
    public static void main(String[] args) throws IOException {
    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringBuilder sb = new StringBuilder();
    	
    	StringTokenizer st = new StringTokenizer(br.readLine(), " ");
    	
    	N = Integer.parseInt(st.nextToken()); // 지도의 세로 크기
    	M = Integer.parseInt(st.nextToken()); // 지도의 가로 크기
    	
    	// 주사위 놓은 곳의 좌표
    	x = Integer.parseInt(st.nextToken()); 
    	y = Integer.parseInt(st.nextToken());
    	
    	// 명령의 개수
    	K = Integer.parseInt(st.nextToken()); 
    	
    	map = new int[N][M];
    	for(int i=0; i<N; i++) {
    		st = new StringTokenizer(br.readLine(), " ");
    		for(int j=0; j<M; j++) {
    			map[i][j] = Integer.parseInt(st.nextToken());
    		}
    	}
    	
    	// 처음엔 주사위에 0만 적혀있다.
    	dice = new int[]{0, 0, 0, 0, 0, 0};
    	
    	st = new StringTokenizer(br.readLine(), " ");
    	// 명령을 순서대로 수행
    	for(int i=0; i<K; i++) {
    		int order = Integer.parseInt(st.nextToken());
    		
    		int nowX = x;
    		int nowY = y;
    		
    		// 주사위 바닥 면의 다음 좌표를 구함
    		moveFloor(order);
    		
    		// 만약 좌표가 범위를 벗어났다면
    		// 다시 이전의 좌표로 되돌리고 continue
    		if(x < 0 || y < 0 || x >= N || y >= M) {
    			x = nowX;
    			y = nowY;
    			continue;
    		}
    		
    		// 주사위를 명령에 맞춰 굴린 다음의 상태를 구함
    		int[] nDice = moveDice(order);
    		
    		dice = nDice;
    		
    		// 만약 이동한 칸에 적힌 숫자가 0이라면
    		if(map[x][y] == 0) {
    			// 주사위의 밑 면에 적힌 숫자를 칸에 복사함
    			map[x][y] = dice[5];
    		} 
    		// 이동한 칸에 적힌 숫자가 0이 아니라면
    		else {
    			// 주사위의 바닥 면에 칸에 적힌 숫자를 복사함
    			dice[5] = map[x][y];
    			// 그 칸의 숫자는 0으로 갱신함
    			map[x][y] = 0;
    		}
    		
    		// 주사위의 윗 면에 적혀 있는 숫자만 StringBuilder에 넣음
    		sb.append(dice[0]).append("\n");
    	}
    	
    	System.out.println(sb);
    }
    
    // 주사위 바닥 면의 다음 좌표를 구하는 메소드
    static void moveFloor(int order) {
    	switch(order) {
    		// 동쪽으로 굴림
	    	case 1:
	    		y++;
	    		break;
	    	// 서쪽으로 굴림
	    	case 2:
	    		y--;
	    		break;
	    	// 북쪽으로 굴림
	    	case 3:
	    		x--;
	    		break;
	    	// 남쪽으로 굴림
	    	case 4:
	    		x++;
	    		break;
	    	default:
	    		break;
    	}
    }
  
    // 명령에 따라 주사위 면의 위치를 갱신하는 메소드
    static int[] moveDice(int order) {
    	int[] nDice = new int[6];
    	
    	switch(order) {
    		// 동쪽으로 굴림
	    	case 1:
	    		nDice[0] = dice[2];
	    		nDice[1] = dice[0];
	    		nDice[2] = dice[5];
	    		nDice[3] = dice[3];
	    		nDice[4] = dice[4];
	    		nDice[5] = dice[1];
	    		break;
	    		
	    	// 서쪽으로 굴림
	    	case 2:
	    		nDice[0] = dice[1];
	    		nDice[1] = dice[5];
	    		nDice[2] = dice[0];
	    		nDice[3] = dice[3];
	    		nDice[4] = dice[4];
	    		nDice[5] = dice[2];
	    		break;
	    		
	    	// 북쪽으로 굴림	
	    	case 3:
	    		nDice[0] = dice[3];
	    		nDice[1] = dice[1];
	    		nDice[2] = dice[2];
	    		nDice[3] = dice[5];
	    		nDice[4] = dice[0];
	    		nDice[5] = dice[4];
	    		break;
	    		
	    	// 남쪽으로 굴림
	    	case 4:
	    		nDice[0] = dice[4];
	    		nDice[1] = dice[1];
	    		nDice[2] = dice[2];
	    		nDice[3] = dice[0];
	    		nDice[4] = dice[5];
	    		nDice[5] = dice[3];
	    		break;
	    		
	    	default:
	    		break;
    	}
    	
    	return nDice;
    }
    
}

정리

  • 주사위를 굴린 뒤에 각 면의 상태를 갱신해주는 방법에 대해 고민을 많이 했다.
  • 이러한 상황에 적절한 자료구조가 있을까 고민을 해봤는데 배열을 사용하는 것이 가장 쉬웠다.
post-custom-banner

0개의 댓글