코딩테스트/구현(Implementation)

[Java] 백준 5373번 : 큐빙

sujin7837 2022. 4. 15. 23:39
반응형

문제

루빅스 큐브는 삼차원 퍼즐이다. 보통 루빅스 큐브는 3×3×3개의 작은 정육면체로 이루어져 있다. 퍼즐을 풀려면 각 면에 있는 아홉 개의 작은 정육면체의 색이 동일해야 한다.

큐브는 각 면을 양방향으로 90도 만큼 돌릴 수 있도록 만들어져 있다. 회전이 마친 이후에는, 다른 면을 돌릴 수 있다. 이렇게 큐브의 서로 다른 면을 돌리다 보면, 색을 섞을 수 있다.

이 문제에서는 루빅스 큐브가 모두 풀린 상태에서 시작한다. 윗 면은 흰색, 아랫 면은 노란색, 앞 면은 빨간색, 뒷 면은 오렌지색, 왼쪽 면은 초록색, 오른쪽 면은 파란색이다.

루빅스 큐브를 돌린 방법이 순서대로 주어진다. 이때, 모두 돌린 다음에 가장 윗 면의 색상을 구하는 프로그램을 작성하시오.

위의 그림은 루빅스 큐브를 푼 그림이다. 왼쪽 면은 시계방향으로 조금 돌려져 있는 상태이다.

입력

첫째 줄에 테스트 케이스의 개수가 주어진다. 테스트 케이스는 최대 100개이다. 각 테스트 케이스는 다음과 같이 구성되어져 있다.

  • 첫째 줄에 큐브를 돌린 횟수 n이 주어진다. (1 ≤ n ≤ 1000)
  • 둘째 줄에는 큐브를 돌린 방법이 주어진다. 각 방법은 공백으로 구분되어져 있으며, 첫 번째 문자는 돌린 면이다. U: 윗 면, D: 아랫 면, F: 앞 면, B: 뒷 면, L: 왼쪽 면, R: 오른쪽 면이다. 두 번째 문자는 돌린 방향이다. +인 경우에는 시계 방향 (그 면을 바라봤을 때가 기준), -인 경우에는 반시계 방향이다.

출력

각 테스트 케이스에 대해서 큐브를 모두 돌린 후의 윗 면의 색상을 출력한다. 첫 번째 줄에는 뒷 면과 접하는 칸의 색을 출력하고, 두 번째, 세 번째 줄은 순서대로 출력하면 된다. 흰색은 w, 노란색은 y, 빨간색은 r, 오렌지색은 o, 초록색은 g, 파란색은 b.

예제 입력 1

4
1
L-
2
F+ B+
4
U- D- L+ R+
10
L- U- L+ U- L- U- U- L+ U+ U+

예제 출력 1

rww
rww
rww
bbb
www
ggg
gwg
owr
bwb
gwo
www
rww

 

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

public class Main {

	private static BufferedReader br;
	private static StringTokenizer st;

	private static int T, N;
	private static Map<Character, Integer> color=new HashMap<>();
	private static char[] colors = { 'w', 'y', 'r', 'o', 'g', 'b' };
	private static char[] direct= {'U', 'D', 'F', 'B', 'L', 'R'};
	private static char[][][] cubes;

	public static void main(String[] args) throws NumberFormatException, IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		T = Integer.parseInt(br.readLine());
		for(int i=0;i<6;i++) {	// 큐브 면을 숫자에 매칭
			color.put(direct[i], i);
		}
		
		for (int t = 1; t <= T; t++) {
			init();
			N = Integer.parseInt(br.readLine());
			st = new StringTokenizer(br.readLine());
			for (int n = 0; n < N; n++) {
				String s = st.nextToken();
				char face = s.charAt(0);
				char dir = s.charAt(1);
				rotate(face, dir);
			}
			
			for(int r=0;r<3;r++) {
				for(int c=0;c<3;c++) {
					System.out.print(cubes[0][r][c]);
				}
				System.out.println();
			}
		}
	}

	private static void init() {	// 테스트 시작할 때 큐브를 원상복귀
		cubes = new char[6][3][3];
		for (int i = 0; i < 6; i++) {
			for (int r = 0; r < 3; r++) {
				for (int c = 0; c < 3; c++) {
					cubes[i][r][c] = colors[i];
				}
			}
		}
	}

	private static void rotate(char face, char dir) {	// 큐브 회전 구현
		rotateMain(face, dir);
		if(dir=='-') {	// 반시계 회전
			rotateSide(face);
		} else {	// 시계 회전(반시계 3번 수행)
			for(int i=0;i<3;i++) {
				rotateSide(face);
			}
		}
	}
	
	private static void rotateMain(char face, char dir) {	// face면의 회전
		int idx=color.get(face);
		char [][]newMap=new char[3][3];
		if (face == 'D') {
			if (dir == '+') { // 시계
				newMap[0][0] = cubes[idx][0][2];
				newMap[0][1] = cubes[idx][1][2];
				newMap[0][2] = cubes[idx][2][2];
				newMap[1][0] = cubes[idx][0][1];
				newMap[1][1] = cubes[idx][1][1];
				newMap[1][2] = cubes[idx][2][1];
				newMap[2][0] = cubes[idx][0][0];
				newMap[2][1] = cubes[idx][1][0];
				newMap[2][2] = cubes[idx][2][0];
				for(int r=0;r<3;r++) cubes[idx][r]=newMap[r].clone();
			} else { // 반시계
				newMap[0][0] = cubes[idx][2][0];
				newMap[0][1] = cubes[idx][1][0];
				newMap[0][2] = cubes[idx][0][0];
				newMap[1][0] = cubes[idx][2][1];
				newMap[1][1] = cubes[idx][1][1];
				newMap[1][2] = cubes[idx][0][1];
				newMap[2][0] = cubes[idx][2][2];
				newMap[2][1] = cubes[idx][1][2];
				newMap[2][2] = cubes[idx][0][2];
				for(int r=0;r<3;r++) cubes[idx][r]=newMap[r].clone();
			}
		} else {
			if (dir == '-') { // 반시계
				newMap[0][0] = cubes[idx][0][2];
				newMap[0][1] = cubes[idx][1][2];
				newMap[0][2] = cubes[idx][2][2];
				newMap[1][0] = cubes[idx][0][1];
				newMap[1][1] = cubes[idx][1][1];
				newMap[1][2] = cubes[idx][2][1];
				newMap[2][0] = cubes[idx][0][0];
				newMap[2][1] = cubes[idx][1][0];
				newMap[2][2] = cubes[idx][2][0];
				for(int r=0;r<3;r++) cubes[idx][r]=newMap[r].clone();
			} else { // 시계
				newMap[0][0] = cubes[idx][2][0];
				newMap[0][1] = cubes[idx][1][0];
				newMap[0][2] = cubes[idx][0][0];
				newMap[1][0] = cubes[idx][2][1];
				newMap[1][1] = cubes[idx][1][1];
				newMap[1][2] = cubes[idx][0][1];
				newMap[2][0] = cubes[idx][2][2];
				newMap[2][1] = cubes[idx][1][2];
				newMap[2][2] = cubes[idx][0][2];
				for(int r=0;r<3;r++) cubes[idx][r]=newMap[r].clone();
			}
		}
	}

	private static void rotateSide(char face) {	// face면을 돌리면 함께 돌아가는 옆면 구현 -> 반시계 기준 회전
		if(face=='U') {
			char[] tmp = new char[3];
			for (int i = 0; i < 3; i++) {
				tmp[i] = cubes[3][0][i];
			}
			for (int i = 0; i < 3; i++) {
				cubes[3][0][i] = cubes[5][0][i];
				cubes[5][0][i] = cubes[2][0][i];
				cubes[2][0][i] = cubes[4][0][i];
				cubes[4][0][i] = tmp[i];
			}
		} else if(face=='D') {
			char[] tmp = new char[3];
			for (int i = 0; i < 3; i++) {
				tmp[i] = cubes[3][2][i];
			}
			for (int i = 0; i < 3; i++) {
				cubes[3][2][i]=cubes[4][2][i];
				cubes[4][2][i]=cubes[2][2][i];
				cubes[2][2][i]=cubes[5][2][i];
				cubes[5][2][i]=tmp[i];
			}
		} else if(face=='F') {
			char[] tmp = new char[3];
			for(int i=0;i<3;i++) {
				tmp[i]=cubes[0][2][i];
			}
			for (int i = 0; i < 3; i++) {
				cubes[0][2][i]=cubes[5][i][0];
				cubes[5][i][0]=cubes[1][2][2-i];
				cubes[1][2][2-i]=cubes[4][2-i][2];
				cubes[4][2-i][2]=tmp[i];
			}
		} else if(face=='B') {
			char[] tmp = new char[3];
			for(int i=0;i<3;i++) {
				tmp[i]=cubes[0][0][i];
			}
			for (int i = 0; i < 3; i++) {
				cubes[0][0][i]=cubes[4][2-i][0];
				cubes[4][2-i][0]=cubes[1][0][2-i];
				cubes[1][0][2-i]=cubes[5][i][2];
				cubes[5][i][2]=tmp[i];
			}
		} else if(face=='L') {
			char[] tmp = new char[3];
			for(int i=0;i<3;i++) {
				tmp[i]=cubes[0][i][0];
			}
			for (int i = 0; i < 3; i++) {
				cubes[0][i][0]=cubes[2][i][0];
				cubes[2][i][0]=cubes[1][2-i][0];
				cubes[1][2-i][0]=cubes[3][2-i][2];
				cubes[3][2-i][2]=tmp[i];
			}
		} else if(face=='R') {
			char[] tmp = new char[3];
			for(int i=0;i<3;i++) {
				tmp[i]=cubes[0][2-i][2];
			}
			for (int i = 0; i < 3; i++) {
				cubes[0][2-i][2]=cubes[3][i][0];
				cubes[3][i][0]=cubes[1][i][2];
				cubes[1][i][2]=cubes[2][2-i][2];
				cubes[2][2-i][2]=tmp[i];
			}
		}
	}
}

큐브의 회전을 일일히 구현해주었더니 디버깅이 매우 힘들었습니다 ㅠㅠㅠㅠㅠ

 

1. 각 면의 시작점(기준점)을 정하고 3차원 큐브 배열에 큐브 정보를 저장합니다.

2. 회전하고자 하는 기준면을 회전합니다.

3. 기준면의 사이드 4면의 회전 결과를 저장합니다.

 

회전할 때 반시계 방향만 구현하고, 시계 방향은 반시계 회전을 3번 하는것으로 대체했습니다.

아래 사이트에서 직접 돌려보며 변화를 확인하면 좀 더 이해가 쉬울 것 같습니다.

 

https://rubiks-cube-solver.com/

 

Online Rubik's Cube Solver

The online Rubik's Cube solver calculates the steps needed to solve a scrambled Rubik's Cube. Enter the colors of your puzzle and let the program find the solution

rubiks-cube-solver.com

 

반응형