[백준] 17837. 새로운 게임 2
문제 링크
풀이 과정
문제에서 요구하는 바를 그대로 따라 구현하는 시뮬레이션 문제입니다.
문제를 풀면서 제가 빠뜨렸던 조건들은 다음과 같습니다.
- 말이 이동하려는 칸이 흰색, 빨간색일 경우 같이 이동하는 말들이 있으므로, 이동하는 모든 말들의 현재 좌표를 바꿔주지 않음.
- 이동하려는 칸이 파란색일 경우, 말의 이동 방향을 설정하는 과정을 조건부로 했음. 어느 조건에서는 이동 방향 설정을 하지 않은 채 움직임.
board = new String[N + 1][N + 1];
for (int i = 1; i <= N; i++) {
Arrays.fill(board[i], "");
}
말이 이동할 때 위에 올려져 있는 말도 함께 이동하기 때문에, 이어 붙이기와 부분 자르기가 가능한 문자열 배열을 사용했습니다. 문자열 배열은 기본적으로 null 로 초기화 됩니다. 만약, 공백 문자로 다시 초기화하지 않을 경우, 이후 +=
연산을 하면 n,u,l,l 을 이어 붙인 문자열 null
이 되므로 유의해야 했습니다.
color = new int[N + 1][N + 1];
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
color[i][j] = sc.nextInt();
}
}
color
배열에는 입력받은 칸의 색 정보가 저장됩니다.
for (int i = 0; i < K; i++) {
marker[i][0] = sc.nextInt();
marker[i][1] = sc.nextInt();
marker[i][2] = sc.nextInt();
board[marker[i][0]][marker[i][1]] = Integer.toString(i);
}
marker
배열은 말의 정보를 저장하는 배열입니다. 0번 인덱스에는 행, 1번 인덱스에는 열, 2번 인덱스에는 이동 방향을 저장합니다. 또한, board
배열에 초기 말의 인덱스를 문자열로 변환해 저장합니다.
while (++turn <= 1000) {
for (int i = 0; i < K; i++) {
int now_i = marker[i][0];
int now_j = marker[i][1];
int now_dir = marker[i][2];
int next_i = now_i + di[now_dir];
int next_j = now_j + dj[now_dir];
if (!check(next_i, next_j) || color[next_i][next_j] == 2) {
marker[i][2] = now_dir = changeDirection(now_dir);
int next_next_i = now_i + di[now_dir];
int next_next_j = now_j + dj[now_dir];
if (check(next_next_i, next_next_j) && color[next_next_i][next_next_j] != 2) {
move(i, now_i, now_j, next_next_i, next_next_j);
}
}
else {
move(i, now_i, now_j, next_i, next_j);
}
}
if (exit) break;
}
천 번동안 턴을 증가시키며 말들을 순차적으로 이동시킵니다.
if (!check(next_i, next_j) || color[next_i][next_j] == 2) {
marker[i][2] = now_dir = changeDirection(now_dir);
int next_next_i = now_i + di[now_dir];
int next_next_j = now_j + dj[now_dir];
if (check(next_next_i, next_next_j) && color[next_next_i][next_next_j] != 2) {
move(i, now_i, now_j, next_next_i, next_next_j);
}
}
말이 이동하려는 칸이 체스판을 벗어나거나, 파란색 칸인 경우, changeDirection
메소드를 통해 이동 방향을 변경하고, 변경된 이동 방향을 marker[i][2] 에 갱신합니다. 이동 방향을 변경하고 나서는 문제 조건에 따라 한 칸을 더 이동시킵니다. 대신, 이동하려는 칸이 체스판을 벗어나거나, 파란색 칸이면 이동하지 않습니다.
else {
move(i, now_i, now_j, next_i, next_j);
}
말이 이동하려는 칸이 체스판을 벗어나지도, 파란색도 아닌 경우, move
메소드를 호출해 한 칸 이동을 합니다.
private static void move(int k, int now_i, int now_j, int next_i, int next_j) {
int beginIndex = board[now_i][now_j].indexOf(Integer.toString(k));
for (int i = beginIndex; i < board[now_i][now_j].length(); i++) {
int num = Integer.parseInt(String.valueOf(board[now_i][now_j].charAt(i)));
marker[num][0] = next_i;
marker[num][1] = next_j;
}
if (color[next_i][next_j] == 0) {
board[next_i][next_j] += board[now_i][now_j].substring(beginIndex);
}
else if (color[next_i][next_j] == 1) {
StringBuilder sb = new StringBuilder(board[now_i][now_j].substring(beginIndex));
board[next_i][next_j] += sb.reverse();
}
board[now_i][now_j] = board[now_i][now_j].substring(0, beginIndex);
if (board[next_i][next_j].length() >= 4) {
exit = true;
}
}
위는 move
메소드 입니다. 현재 말 번호(k), 현재 말의 좌표(now_i, now_j), 이동하려는 칸의 좌표(next_i, next_j) 를 파라미터로 받습니다. 체스판내 말이 위치하는 좌표에서 말 번호를 통해 말의 위치( beginIndex
) 를 찾습니다. 이후, 해당 말을 기준으로 위에 있는 말들의 좌표들을 이동하려는 칸의 좌표로 모두 바꿔줍니다.
이동하려는 칸이 흰 색인 경우 +=
연산을 통해 맨 위에 올려 놓고, 빨간색인 경우는 reverse
메소드를 호출해뒤집고 난 뒤 +=
연산을 통해 맨 위에 올려 놓습니다.
원래 좌표에 존재했던 말들은 제거하고, 이동한 칸의 말의 개수를 세어, 그 개수가 4개 이상이면 종료합니다.
코드
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N, K;
static int[][] color;
static int[][] marker;
static String[][] board;
static int[] di = {0, 0, 0, -1, 1};
static int[] dj = {0, 1, -1, 0, 0};
static boolean exit;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
K = sc.nextInt();
color = new int[N + 1][N + 1];
marker = new int[K][3];
board = new String[N + 1][N + 1];
for (int i = 1; i <= N; i++) {
Arrays.fill(board[i], "");
}
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
color[i][j] = sc.nextInt();
}
}
for (int i = 0; i < K; i++) {
marker[i][0] = sc.nextInt();
marker[i][1] = sc.nextInt();
marker[i][2] = sc.nextInt();
board[marker[i][0]][marker[i][1]] = Integer.toString(i);
}
int turn = 0;
while (++turn <= 1000) {
for (int i = 0; i < K; i++) {
int now_i = marker[i][0];
int now_j = marker[i][1];
int now_dir = marker[i][2];
int next_i = now_i + di[now_dir];
int next_j = now_j + dj[now_dir];
if (!check(next_i, next_j) || color[next_i][next_j] == 2) {
marker[i][2] = now_dir = changeDirection(now_dir);
int next_next_i = now_i + di[now_dir];
int next_next_j = now_j + dj[now_dir];
if (check(next_next_i, next_next_j) && color[next_next_i][next_next_j] != 2) {
move(i, now_i, now_j, next_next_i, next_next_j);
}
}
else {
move(i, now_i, now_j, next_i, next_j);
}
}
if (exit) break;
}
System.out.println(exit ? turn : -1);
}
private static void move(int k, int now_i, int now_j, int next_i, int next_j) {
int beginIndex = board[now_i][now_j].indexOf(Integer.toString(k));
for (int i = beginIndex; i < board[now_i][now_j].length(); i++) {
int num = Integer.parseInt(String.valueOf(board[now_i][now_j].charAt(i)));
marker[num][0] = next_i;
marker[num][1] = next_j;
}
if (color[next_i][next_j] == 0) {
board[next_i][next_j] += board[now_i][now_j].substring(beginIndex);
}
else if (color[next_i][next_j] == 1) {
StringBuilder sb = new StringBuilder(board[now_i][now_j].substring(beginIndex));
board[next_i][next_j] += sb.reverse();
}
board[now_i][now_j] = board[now_i][now_j].substring(0, beginIndex);
if (board[next_i][next_j].length() >= 4) {
exit = true;
}
}
private static boolean check(int i, int j) {
if (i < 1 || i > N || j < 1 || j > N) return false;
return true;
}
private static int changeDirection(int dir) {
if (dir == 1) return 2;
else if (dir == 2) return 1;
else if (dir == 3) return 4;
else return 3;
}
}
댓글남기기