코딩테스트/Java

[JAVA] 백준 주사위 굴리기

SK_MOUSE 2021. 5. 27. 15:01

구현 문제이다.

3차원의 주사위를 2차원의 평면에서 굴려가며 각 면의 숫자를 계산하는 방식이다.

 

한번 이 방법을 알아두면 나중에는 좀 겁이 덜 나게 풀 수 있을 것 같다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

class Main {
    private static int n, m, x, y, k;
    private static int[][] map;
    private static int[] dirList;
    private static final int[] dx = {0, 0, 0, -1, 1};
    private static final int[] dy = {0, 1, -1, 0, 0};

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        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];
        dirList = new int[k];
        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());
            }
        }
        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < k; i++) {
            dirList[i] = Integer.parseInt(st.nextToken());
        }
        solution(new Dice());
    }

    private static void solution(Dice dice) {
        int dir, nx = x, ny = y;
        for (int i = 0; i < k; i++) {
            dir = dirList[i];
            if (!isValid(nx + dx[dir], ny + dy[dir])) continue;
            nx = nx + dx[dir];
            ny = ny + dy[dir];
            dice.turn(dir);//주사위를 움직인다.
            //이동한 칸에 쓰여 있는 수가 0이면, 주사위의 바닥면에 쓰여 있는 수가 칸에 복사된다.
            if (map[nx][ny] == 0) map[nx][ny] = dice.getNum(7 - dice.up);
            //0이 아닌 경우에는 칸에 쓰여 있는 수가 주사위의 바닥면으로 복사되며, 칸에 쓰여 있는 수는 0이 된다.
            else {
                dice.setNum(7 - dice.up, map[nx][ny]);
                map[nx][ny] = 0;
            }
            System.out.println(dice.getNum(dice.up));
        }
    }

    private static boolean isValid(int x, int y) {
        return x >= 0 && y >= 0 && x < n && y < m;
    }
}

class Dice {
    int[] nums;
    int up, right, front;

    Dice() {
        nums = new int[6];
        up = 1;
        right = 3;
        front = 5;
    }

    void turn(int dir) {
        int temp = up;
        switch (dir) {
            case 1://동(우)
                up = 7 - right;//왼쪽에있는면을 맨위로 올림(7-오른쪽)
                right = temp;
                break;
            case 2://서(좌)
                up = right;//오른쪽에 있는면을 맨위로 올림
                right = 7 - temp;
                break;
            case 3://북(상)
                up = front;//앞쪽에 있는면이 위로(위의방향으로 굴러가니깐)
                front = 7 - temp;
                break;
            case 4://남(하)
                up = 7 - front;//앞에있는면의 반대편면이 맨앞으로 감(7-뒷쪽)
                front = temp;
                break;
        }
    }

    void setNum(int num, int value) {
        nums[num - 1] = value;
    }

    int getNum(int num) {
        return nums[num - 1];
    }
}

위의 코드에서 중요하게 볼 부분은 class Dice에서 void turn(int dir)메소드이다.

 

up=1 front=5 right=3

코드를 살펴보면 정반대편 면의 값은 7-해당면을 하면 값이 나온다.

위 그림의 예로 보면 바닥면을 구하면, 7-up = 7-1 = 6 이다.

 

테스트케이스1을 예로 잡았다.

2*4 좌표계

자 그럼 굴려보겠다.

남쪽방향(case 4)으로 굴려보겠다.

굴리기 전을 A, 굴리고 난 후를 B라고 하겠다.

 

upA=1, frontA=5, rightA=3에서

 

case 4의 계산식대로 대입해보면 아래와 같다.

 

upB=7-front=7-5 =2 (앞쪽의 있는면의 반대편면, 즉 뒷쪽의 면이 윗면으로 올라온다.)

frontB=temp=이전up=1

그리고 rightB는 위아래로 굴리는경우 변함이 없으므로 계속 3이다.

 

따라서

upB=2, frontB=1, rightB=3

 

 

 

이러한 방식대로 이루어져있다. 다른 경우도 모두 이와 마찬가지로 주사위를 굴릴때 규칙성을 찾아내는것이 중요한 관건이다.

 

 

코드 출처 : https://leveloper.tistory.com/88

주사위 : http://www.magicmgmt.com/gary/dice/one_die_image.html

 

반응형

'코딩테스트 > Java' 카테고리의 다른 글

[JAVA] 백준 드래곤 커브  (0) 2021.06.03
[JAVA] 백준 테트로미노  (0) 2021.06.01
[JAVA] 백준 연구소 DFS+BFS  (3) 2021.05.10
[JAVA] 백준 후위표기식  (0) 2021.05.04
[JAVA] 백준 마법사 상어와 파이어볼  (0) 2021.04.29