[BaekJoon] 14499 주사위 굴리기 (Java)

오태호·2022년 9월 7일
0

백준 알고리즘

목록 보기
52/395

1.  문제 링크

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

2.  문제



요약

  • 크기가 NxM인 지도가 존재하고, 지도의 오른쪽은 동쪽, 위쪽은 북쪽은 나타냅니다.
  • 지도의 좌표는 (r, c)로 나타내며, r은 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수입니다.
  • 지도의 위에 주사위가 하나 놓여져있으며, 주사위 전개도는 아래와 같습니다.
	2
4	1	3
	5
   	6
  • 주사위는 지도 위에 윗 면이 1이고, 동쪽을 바라보는 방향이 3인 상태로 놓여져 있으며, 놓여져 있는 곳의 좌표는 (x, y)입니다.
  • 처음에 주사위에는 모든 면에 0이 적혀 있습니다.
  • 지도의 각 칸에는 정수가 하나씩 쓰여져 있고, 주사위를 굴렸을 때 이동한 칸에 쓰여있는 수가 0이면 주사위의 바닥면에 쓰여있는 수가 칸에 복사되고, 0이 아닌 경우에는 칸에 쓰여있는 수가 주사위의 바닥면으로 복사되며, 칸에 쓰여있는 수는 0이 됩니다.
  • 주사위를 지도의 바깥으로 이동시키려고 한다면 해당 명령을 무시해야 하며, 출력도 하지 않습니다.
  • 주사위를 놓은 곳의 좌표와 이동시키는 명령이 주어졌을 때, 주사위가 이동했을 때마다 상단에 쓰여있는 값을 구하는 문제입니다.
  • 입력: 첫 번째 줄에 1보다 크거나 같고 20보다 작거나 같은 지도의 세로 크기 N, 가로 크기 M, 주사위를 놓은 곳의 좌표 x, y, 1보다 크거나 같고 1,000보다 작거나 같은 명령의 개수 K가 주어지고 두 번째 줄부터 N개의 줄에는 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어지며 마지막 줄에는 이동하는 명령이 순서대로 주어집니다.
    • 주사위를 놓은 곳의 좌표는 0xN1,0yM10 ≤ x ≤ N - 1, 0 ≤ y ≤ M - 1 범위 내에 존재합니다.
    • 주사위를 놓은 칸에 쓰여있는 수는 항상 0입니다.
    • 지도의 각 칸에 쓰여있는 수는 10 미만의 자연수 또는 0입니다.
    • 명령은 동쪽은 1, 서쪽은 2, 북쪽은 3, 남쪽은 4로 주어집니다.
  • 출력: 이동할 때마다 주사위의 윗 면에 쓰여있는 수를 출력합니다.
    • 바깥으로 이동시키려는 경우는 해당 명령을 무시해야 하며, 출력도 하지 않습니다.

3.  소스코드

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

public class Main {
	static StringBuilder sb = new StringBuilder();
	static int N, M, x, y, K, front = 2, left = 4, right = 3, behind = 5, bottom = 6, top = 1;
	static int[][] map;
	static int[] order, values = new int[7], opposite = new int[] {0, 6, 5, 4, 3, 2, 1};
	static ArrayList<Integer> top_values;
	static void input() {
		Reader scanner = new Reader();
		top_values = new ArrayList<>();
		N = scanner.nextInt();
		M = scanner.nextInt();
		map = new int[N][M];
		x = scanner.nextInt();
		y = scanner.nextInt();
		K = scanner.nextInt();
		order = new int[K];
		for(int i = 0; i < N; i++) {
			for(int j = 0; j < M; j++) {
				map[i][j] = scanner.nextInt();
			}
		}
		for(int i = 0; i < K; i++) order[i] = scanner.nextInt();
	}
	
	static void solution() {
		for(int i = 0; i < K; i++) {
			if(order[i] == 1) {
				if(canMove(x, y + 1)) {
					moveRight(x, y + 1);
					y++;
				}
			} else if(order[i] == 2) {
				if(canMove(x, y - 1)) {
					moveLeft(x, y - 1);
					y--;
				}
			} else if(order[i] == 3) {
				if(canMove(x - 1, y)) {
					moveUp(x - 1, y);
					x--;
				}
			} else if(order[i] == 4) {
				if(canMove(x + 1, y)) {
					moveDown(x + 1, y);
					x++;
				}
			}
		}
		for(int value : top_values) sb.append(value).append('\n');
		System.out.print(sb);
	}
	
	static void moveRight(int x, int y) {
		changeDiceDirection(front, bottom, top, behind, right, left);
		if(map[x][y] == 0) changeMapValue(x, y);
		else changeDiceValue(x, y);
		findTopValue();
	}
	
	static void moveLeft(int x, int y) {
		changeDiceDirection(front, top, bottom, behind, left, right);
		if(map[x][y] == 0) changeMapValue(x, y);
		else changeDiceValue(x, y);
		findTopValue();
	}
	
	static void moveUp(int x, int y) {
		changeDiceDirection(bottom, left, right, top, behind, front);
		if(map[x][y] == 0) changeMapValue(x, y);
		else changeDiceValue(x, y);
		findTopValue();
	}
	
	static void moveDown(int x, int y) {
		changeDiceDirection(top, left, right, bottom, front, behind);
		if(map[x][y] == 0) changeMapValue(x, y);
		else changeDiceValue(x, y);
		findTopValue();
	}
	
	static boolean canMove(int x, int y) {
		if(0 <= x && x < N && 0 <= y && y < M) return true;
		return false;
	}
	
	static void changeDiceDirection(int next_front, int next_left, int next_right, int next_behind, int next_bottom, int next_top) {
		front = next_front;
		left = next_left;
		right = next_right;
		behind = next_behind;
		bottom = next_bottom;
		top = next_top;
	}
	
	static void changeDiceValue(int x, int y) {
		values[bottom] = map[x][y];
		map[x][y] = 0;
	}
	
	static void changeMapValue(int x, int y) {
		map[x][y] = values[bottom];
	}
	
	static void findTopValue() {
		top_values.add(values[top]);
	}
	
	public static void main(String[] args) {
		input();
		solution();
	}
	
	static class Reader {
		BufferedReader br;
		StringTokenizer st;
		public Reader() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
	}
}

4.  접근

  • 주어진 명령들을 순서대로 진행하면서 명령을 진행한 후에 상단에 쓰여있는 값들을 출력합니다.

solution 함수

static void solution() {
	for(int i = 0; i < K; i++) {
		if(order[i] == 1) {
			if(canMove(x, y + 1)) {
				moveRight(x, y + 1);
				y++;
			}
		} else if(order[i] == 2) {
			if(canMove(x, y - 1)) {
				moveLeft(x, y - 1);
				y--;
			}
		} else if(order[i] == 3) {
			if(canMove(x - 1, y)) {
				moveUp(x - 1, y);
				x--;
			}
		} else if(order[i] == 4) {
			if(canMove(x + 1, y)) {
				moveDown(x + 1, y);
				x++;
			}
		}
	}
	for(int value : top_values) sb.append(value).append('\n');
	System.out.print(sb);
}
  • solution 함수에서는 주어진 명령들을 처음부터 보면서 어느 방향으로 이동하는 명령인지 확인하고 해당 방향으로 이동했을 때 지도 바깥으로 나가는지 확인하여 그렇지 않다면 해당 방향으로 움직이도록 합니다.
  • 각 명령에서 상단에 쓰여있는 값을 top_values에 저장하고 모든 명령을 수행했을 때, top_values에 있는 값들을 출력합니다.

canMove 함수

static boolean canMove(int x, int y) {
	if(0 <= x && x < N && 0 <= y && y < M) return true;
	return false;
}
  • canMove 함수는 명령에 맞는 방향으로 주사위를 옮겼을 때, 그 위치가 지도 바깥인지를 판별하는 함수입니다.
  • 만약 바깥이라면 false를, 그렇지 않다면 true를 반환합니다.

changeDiceDirection 함수

static void changeDiceDirection(int next_front, int next_left, int next_right, int next_behind, int next_bottom, int next_top) {
	front = next_front;
	left = next_left;
	right = next_right;
	behind = next_behind;
	bottom = next_bottom;
	top = next_top;
}
  • 이 함수는 명령에 맞는 방향으로 움직였을 때, 주사위가 보는 방향을 변경해주는 함수입니다.
  • 예를 들어, 주사위가 남쪽으로 움직였다면, 상단에 위치한 면은 앞면이 될 것이고, 하단에 위치한 면은 뒷면이 될 것이며, 앞면은 하단에 위치한 면이, 뒷면은 상단에 위치한 면이 될 것입니다.
  • 이렇게 주사위가 이동할 때마다 주사위의 각 면이 바라보는 방향이 달라질텐데, 이를 변경해주는 함수입니다.

changeDiceValue 함수

static void changeDiceValue(int x, int y) {
	values[bottom] = map[x][y];
	map[x][y] = 0;
}
  • 이 함수는 명령에 맞는 방향으로 움직이고 나서 주사위가 있는 위치의 지도의 값이 0이 아닐 때 지도에 있는 값을 주사위 하단에 복사하는 작업을 하는 함수입니다.
  • 지도에 있는 값을 주사위 하단에 복사하고 지도에 있는 값은 0으로 변경됩니다.

changeMapValue 함수

static void changeMapValue(int x, int y) {
	map[x][y] = values[bottom];
}
  • 이 함수는 명령에 맞는 방향으로 움직이고 나서 주사위가 있는 위치의 지도의 값이 0일 때 주사위 하단에 위치한 면의 값을 지도에 복사하는 함수입니다.

findTopValue 함수

static void findTopValue() {
	top_values.add(values[top]);
}
  • 이 함수는 명령을 실행하고 난 후 상단에 위치한 값을 뽑아내어 이를 top_values에 넣는 함수입니다.

move~ 함수

static void moveRight(int x, int y) {
	changeDiceDirection(front, bottom, top, behind, right, left);
	if(map[x][y] == 0) changeMapValue(x, y);
	else changeDiceValue(x, y);
	findTopValue();
}
  • move류의 함수는 명령에 맞는 방향으로 이동하여 명령을 수행하는 함수입니다.
  • 동쪽으로 이동하는 명령을 예시로 보면
    1. changeDiceDirection 함수를 통해 주사위가 동쪽으로 이동했을 때 변화하는 각 면이 바라보는 방향을 변경해줍니다.
    1. 주사위가 이동한 곳의 지도의 값이 0인지 아닌지 체크합니다.
      • 만약 0이라면 changeMapValue 함수를 통해 주사위 하단에 위치한 면의 값을 지도에 복사합니다.
      • 만약 0이 아니라면 changeDiceValue 함수를 통해 지도의 값을 주사위 하단에 위치한 면에 복사하고 지도의 값을 0으로 만들어줍니다.
    2. 주사위의 이동과 값 변경을 완료하였으니 findTopValue 함수를 통해 주사위 상단에 위치한 값을 뽑고 이를 top_values에 넣어줍니다.
profile
자바, 웹 개발을 열심히 공부하고 있습니다!

0개의 댓글