글 작성자: 개발섭

이번 문제는 삼성 SW역량테스트 기출문제인 주사위 굴리기입니다. 시뮬레이션 문제 방식으로 문제를 풀면 됩니다.

저도 처음에는 이 시뮬레이션 문제를 어떤식으로 풀어야할지 감을 잘 못잡았는데요.

푸는 방식은 간단하게 케이스를 나눠서 생각해보고, 순차적으로 문제를 어떤식으로 진행할지를 생각해보고, 문제를 접근하는 편이 좋습니다. 

여기서 시뮬레이션에서 가장 큰 골격은 3가지의 루틴으로 진행됩니다.

  • 1. 지도상에서 주사위를 이동시켜봅니다.
    • 1-1. 지도상에서 주사위가 밖으로 이동한 경우. 무시합니다.
  • 2. 지도상에서 주사위가 밖으로 이동하지 않은 경우 이동 방향에 따라서 이동합니다.
  • 3. 주사위의 아래쪽은 Map의 경우에 따라 그값을 복사하거나 복사해줍니다. 그 이후에 주사위 상단의 값을 출력합니다.

이 루틴을 명확하게 지키는 선에서 코드를 짜면 됩니다.

이 문제에서는 주사위를 어떤식으로 만들까? 가 핵심입니다. 주사위를 어떤식으로 만들어야하는가를 고민을 해봤는데, 

내가 추측한 방식중 가장 좋은 방식은 세로열과 가로열을 따로 만들어서 주사위를 생각하면 된다는 것.

주사위는 어쨌든간에 + 십자 모양이고 결국에는 상단과 하단은 세로열과 가로열이 공유를 하게되는 모습을 가지고 있으므로, 

세로배열과 가로 배열을 두개를 만들어서 그 안에서 값이 어떤식으로 이동하는지를 체크하여, 값을 출력하면 된다고 생각했다.

 

당시에 코드짠답시고 별의 별짓을 다해봤던 것.

결국에는 우리는 동서남북으로만 굴리면 되고, 거기에 하단과 상단만 생각하면 됩니다

그림을 그려서 보는게 가장 이해가 쉬울것 같아서 그림을 그렸고, 그림의 기준은 백준에 그려져있는 십자 숫자를 기준으로 삼고 그렸다.

세로열이 북쪽 이동하거나 남쪽 이동할때 면의 이동방식.

십자의 세로만 따로 때서 생각해보면 위와 같은 그림이 될 것 입니다. 십자의 가로만따로 때서 그린 것은 가로열이 되는 것입니다.

북쪽으로 구를때 한칸씩 위로 옮겨가고 맨위의 2는 맨뒤로 이동하고, 남쪽으로 구를때는 아래로 한칸씩 옮겨가면서 맨아래의 6은 맨위로 이동합니다. 

비슷한 방식으로 가로열도 같은 방식으로 이동한다.

세로열
가로열

근데 우리는 주사위 상단과 하단이 가장 중요하기 때문에 그 위치를 파악이 되야한다. 

초록색은 주사위 하단  분홍색은 주사위 상단지점이다.

가로열과 세로열 기본포지션 상태에서 초록색과 분홍색은 동일하다. 

이걸 초점을 맞춰서 계속 세로열과 가로열의 초록색과 분홍색의 값을 계속 맞춰주는 것이 중요합니다.

결과적으로 값을 받아오면 이동방향에 따라서 이동하고 출력하는 방식으로 시뮬레이션을 진행 시킬 수 있습니다. 

시뮬레이션을 진행시키고 종료시키는 핵심은 명령어를 얼만큼 받았는지입니다. 여기서 명령어는 "어느방향으로 굴릴지를 알려주는 것" 입력의 마지막 줄이 핵심 명령어가 되므로, 잘 파악해서 코드를 짜야합니다.

 

저는

  • 1. 지도상에서 주사위를 이동시켜봅니다. => map[x][y] != -1 지정된 방향으로 이동합니다. 
    • 1-1. 지도상에서 주사위가 밖으로 이동한 경우. 무시합니다. => map[x][y] ==-1 이면 지정된 방향에서 이동 위치에서 뒤로 다시 이동합니다.
  • 2. 지도상에서 주사위가 밖으로 이동하지 않은 경우 이동 방향에 따라서 이동합니다. => 방향에 따라 세로열을 움직일지 혹은 가로열을 움직일지 확인 해봅니다. 
  • 3. 주사위의 아래쪽은 Map의 경우에 따라 그값을 복사하거나 복사해줍니다. 그 이후에 주사위 상단의 값을 출력합니다. => 주사위의 열을 이동한 후에 아래면을 복사하거나, 윗열을 출력합니다. 

볼드처리한 방식으로 코드를 작성하였고, 세로열이 움직이는 방식은 남방향이나 북방향에 따라서 이동방식이 달라지고 똑같이 가로열역시 동방향이냐 서방향에 따라서 움직이는 방식이 다릅니다. (세로열과 가로열 그림의 화살표 방식을 배열로 움직인다고 생각하면 쉽습니다.)

 

코드별로 너무 길어져서 출력하는 것은 함수로 따로 빼서 만들었고, 지속적으로 출력하는 방식과 아랫면을 복사하는 방식을 함수화해서 만들었던 코드입니다.

 


package codeBaekJoon;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

public class No14499_diceRolling {
	static int n,m,x,y,k;
	static int [][] map;
	static int sero[] = new int [4];
	static int garo[] = new int [4];
	static int dx[]= {0,0,0,-1,1};
	static int dy[] ={0,1,-1,0,0}; //1,2,3,4에 따른 방향성.

	//세로면의 바닥면은 주사위에 가져오고 상단은 출력하는 함수.
	static void seroPrint(int i, int j){
		if(map[i][j]==0){
			map[i][j] = sero[1];
			garo[1] = sero[1];
		}
		else{ //0이 아니라면
			sero[1] = map[i][j];
			garo[1] = sero[1];
			map[i][j] = 0;
		}
		System.out.println(sero[3]);
	}

	//가로면의 바닥면은 주사위에 가져오고 상단은 출력하는 함수.
	static void garoPrint(int i, int j){
		if(map[i][j]==0){
			map[i][j]= garo[1];
			sero[1] = garo[1];
		}
		else{
			garo[1] = map[i][j];
			sero[1] = garo[1];
			map[i][j] =0;
		}
		System.out.println(garo[3]);
	}

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String tc = br.readLine();
		StringTokenizer st= new StringTokenizer(tc, " ");
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		x = Integer.parseInt(st.nextToken())+1;
		y = Integer.parseInt(st.nextToken())+1;
		k = Integer.parseInt(st.nextToken());
		map = new int [n+2][m+2];
		//주사위 면의 숫자 0으로 초기화.
		Arrays.fill(sero, 0);
		Arrays.fill(garo, 0);
		//지도 Mapping
		for(int i=0; i<n+2; i++){
			Arrays.fill(map[i], -1);
		}
		for(int i=1; i<n+1; i++){
			String mapp = br.readLine();
			st = new StringTokenizer (mapp, " ");
			for(int j=1; j<m+1; j++){
				map[i][j] = Integer.parseInt(st.nextToken());
			}
		}
		
		// 방향 받기.
		String d = br.readLine();
		st = new StringTokenizer(d," ");
		for(int i=0; i<k; i++){ // 방향별로 루틴 시작.
			int dir = Integer.parseInt(st.nextToken());
			x +=dx[dir];
			y +=dy[dir];
/*			System.out.println("x, y :"+x+" , "+y+" map[x][y]: "+map[x][y]);
			for(int a=1; a<n+1; a++){
				for(int b=1; b<m+1; b++){
					System.out.print(map[a][b]+" ");
				}
				System.out.println();
			}
			System.out.print("sero[]: ");
			for(int a=0; a<4; a++){
				System.out.print(sero[a]+" ");
			}
			System.out.println();
			System.out.print("garo[]: ");
			for(int a=0; a<4; a++){
				System.out.print(garo[a]+" ");
			}
			System.out.println();*/

			if(map[x][y]!=-1){ //이동시 밖으로 이동하지 않은 경우면 진행. 
				if(dir==1 || dir==2){ //동쪽 과 서쪽.
					if(dir==1){//동쪽.
						int temp = garo[0];
						for(int j=0; j<3; j++){ //가로면의 순서를 섞는 과정.
							garo[j] = garo[j+1];
						}
						garo[3] = temp;
						sero[1] = garo[1];
						sero[3] = garo[3];
						garoPrint(x,y); 
					}
					else{ //서쪽.
						int temp = garo[3];
						for(int j=3; j>0; j--){ //가로면의 순서를 섞는 과정. 반대방향으로.
							garo[j] = garo[j-1];
						}
						garo[0] = temp;
						sero[1] = garo[1];
						sero[3] = garo[3];
						garoPrint(x,y);
					}
				}
				if(dir==3 || dir==4){ //북쪽 과 남쪽.
					if(dir==3){//북쪽.
						int temp = sero[0]; //세로면의 순서를 섞는 과정.
						for(int j=0; j<3; j++){
							sero[j] = sero[j+1];
						}
						sero[3] = temp;
						garo[1] = sero[1];
						garo[3] = sero[3];
						seroPrint(x,y);
					}
					else{ //남쪽.
						int temp = sero[3]; //세로면의 순서를 섞는 과정. 반대방향으로.
						for(int j=3; j>0; j--){
							sero[j] = sero[j-1];
						}
						sero[0] = temp;
						garo[1] = sero[1];
						garo[3] = sero[3];
						seroPrint(x,y); 
					}
				}
			}
			else{
				x -=dx[dir];
				y -=dy[dir];
			}
		}
	}

}