본문 바로가기
PS 문제 풀이/Baekjoon

[BOJ] 백준 14499 주사위 굴리기

by 까망 하르방 2021. 2. 21.
반응형

출처: https://www.acmicpc.net/problem/14499 

 Input 
4 2 0 0 8
0 2
3 4
5 6
7 8
4 4 4 1 3 3 3 2

 Output 

0
0
3
0
0
8
6
3

N x M 크기의 지도 /  주사위를 놓은 곳의 좌표 (x, y) / 명령의 개수 K가 주어집니다.

N x M 지도에는 숫자가 적혀있으며 초기에 주사위가 놓여 있는 곳은 『0』 이다.

마지막 줄에는 이동하는 명령이 순서대로 주어진다.

동: 1 / 서: 2 / 북: 3 / 남: 4

주사위 전개도는 아래와 같으며, 윗 면을 1, 동쪽을 바라보는 방향이 3이라고 정의.

※ 시작할 때 [1]이 윗면, [6]이 아랫면에 해당

* 처음 주어진 주사위의 모든 면에는 0이 적혀져 있습니다. (1 ~ 6 )

 

[주사위를 굴렸을 때]

    이동한 칸에 적혀있는 수가 0이 아닌 경우 

    → 그 숫자가 주사위의 바닥면에 복제되며, 칸에 적혀있는 숫자는 0이 됩니다.

    이동한 칸에 적혀있는 수가 0인 경우

    → 주사위의 바닥면에 쓰여 있는 수가 칸에 복사됩니다.

         (주사위 바닥면 숫자는 변화 X)

주사위를 굴려가며, 윗면 / 아랫면 / 칸의 숫자 변화를 구현 

(+ 지도의 동일한 지점을 중복 방문하더라도 주사위의 상태에 따라 값이 다를 수 있음)

 

Case 분석

이동순서 = { ↓  ↓  ↓  →  ↑  ↑  ↑   }으로 다음과 같습니다.

이때, 이동할 때마다 주사위의 윗면, 아랫면의 상태는 다음과 같습니다.

* 지도를 벗어나는 명령어 주의

 

주사위를 이동할 때마다 Index [2]: 윗면 / Index [6]: 아랫면에 해당되도록 처리

* 나머지 면도 동일한 원리로 처리

동쪽()으로 이동했을 때, Index [4]에 있던 값을 윗면[1] /  Index [3]을 아랫면[6]으로 처리

- 서쪽()으로 이동했을 때, Index [3]에 있던 값을 윗면[1] /  Index [4]을 아랫면[6]으로 처리

- 북쪽()으로 이동했을 때, Index [5]에 있던 값을 윗면[1] /  Index [2]을 아랫면[6]으로 처리

- 남쪽()으로 이동했을 때, Index [2]에 있던 값을 윗면[1] /  Index [5]을 아랫면[6]으로 처리


import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int N = Integer.parseInt(sc.next());
        int M = Integer.parseInt(sc.next());
        
        // 지도(게임판) 입력 받기
        int[][] arr = new int[N][M];

        // 시작 위치 입력 받기
        Dice dice = new Dice();
        dice.setPosition(Integer.parseInt(sc.next()), Integer.parseInt(sc.next()));
        
        // 명령 개수 입력받기
        int K = Integer.parseInt(sc.next());
        
        // 각 칸의 숫자 입력 받기
        for(int i=0; i<N; i++) {
            for(int j=0; j<M; j++) {
                arr[i][j] = Integer.parseInt(sc.next());
            }
        }
                
        for(int i=0; i<K; i++) {
            // 방향 입력받기
            int direction = Integer.parseInt(sc.next());
            
            // 주사위 이동
            if(dice.move(direction, N, M)) continue;
            
            
            // 이동되어진 지도(게임판)의 칸이 0인지 확인
            if(arr[dice.x][dice.y] == 0) {
                // 주사위 뒷면의 숫자를 복사하여 해당 칸에 복사
                arr[dice.x][dice.y] = dice.surface[6].curNum;
            }else {
                // 해당 칸의  숫자를 주사위 아랫면에 복사하고 0으로 전환
                dice.surface[6].curNum = arr[dice.x][dice.y];
                arr[dice.x][dice.y] = 0;
            }
            
            System.out.println(dice.surface[1].curNum);
            
        }

    }
}

class Dice{
    int[] dx, dy;
    int x,y;
    
    // 이동되면서 주사위의 면들이 어딜 향하고 있는지 표시하기 위함
    // (surface[1] 윗면, surface[3]이 오른쪽을 향한다고 가정)
    Surface[] surface;
    
    public Dice() {
        // 동(1), 서(2), 남(4), 북(3)
        // 편의상 인덱스 0번째를 넣어둠
        dx = new int[]{0, 0, 0, -1, 1};
        dy = new int[]{0, 1, -1, 0, 0};
        
        // 초기의 1~6면을 나타낸다.
        surface = new Surface[7];
        for(int i=1; i<=6; i++) {
            surface[i]  = new Surface(i);
        }
    }
    
    public void setPosition(int x, int y) {
        this.x = x;
        this.y = y;

    }
    
    public boolean move(int direction, int N, int M) {
        int next_x = x + dx[direction];
        int next_y = y + dy[direction];
        
        // 범위를 벗어나면 무효!
        if(next_x < 0 || next_y < 0) return true;
        if(next_x >= N || next_y >= M) return true;
        
        // 좌표이동
        setPosition(next_x,next_y);
        
        // 굴리면서 바뀐 방향으로 주사위면을 재설정
        surface = setSuface(direction);
        return false;
    }

    public Surface[] setSuface(int direction) {
        Surface[] temp = new Surface[7];
        if(direction == 1) { // 동쪽
            temp[1] = surface[4]; temp[2] = surface[2]; temp[3] = surface[1];
            temp[4] = surface[6]; temp[5] = surface[5]; temp[6] = surface[3];
        }else if(direction == 2) { // 서쪽
            temp[1] = surface[3]; temp[2] = surface[2]; temp[3] = surface[6];
            temp[4] = surface[1]; temp[5] = surface[5]; temp[6] = surface[4];
        }else if(direction == 3) { // 북쪽
            temp[1] = surface[5]; temp[2] = surface[1]; temp[3] = surface[3];
            temp[4] = surface[4]; temp[5] = surface[6]; temp[6] = surface[2];
        }else if(direction == 4) { // 남쪽
            temp[1] = surface[2]; temp[2] = surface[6]; temp[3] = surface[3];
            temp[4] = surface[4]; temp[5] = surface[1]; temp[6] = surface[5];
        }
        return temp;
    }
}

class Surface{
    // 제일 처음 시작했을 때 놓인 주사위면들이 향했던 방향에 번호를 부여
    // ('1' 윗면 '3'이 오른쪽을 향한다고 가정)
    int initVal;
    // 가지고 있는 숫자
    int curNum;
    
    public Surface(int val) {
        initVal = val;
        // 처음에는 0으로 초기화
        curNum = 0;
    }
}

 

반응형

'PS 문제 풀이 > Baekjoon' 카테고리의 다른 글

[BOJ] 백준 14500 테트로미노  (0) 2021.02.21
[BOJ] 백준 14502 연구소  (0) 2021.02.21
[BOJ] 백준 3190 뱀  (0) 2021.02.21
[BOJ] 백준 12100 2048(Easy)  (0) 2021.02.21
[BOJ] 백준 13460 구슬 탈출 2  (0) 2021.02.21

댓글