본문 바로가기

백준/JAVA

[Baekjoon/JAVA] 1063번 - 킹

Baekjoon Online Judge

문제로 이동

 

문제

8*8크기의 체스판에 왕이 하나 있다. 킹의 현재 위치가 주어진다. 체스판에서 말의 위치는 다음과 같이 주어진다. 알파벳 하나와 숫자 하나로 이루어져 있는데, 알파벳은 열을 상징하고, 숫자는 행을 상징한다. 열은 가장 왼쪽 열이 A이고, 가장 오른쪽 열이 H까지 이고, 행은 가장 아래가 1이고 가장 위가 8이다. 예를 들어, 왼쪽 아래 코너는 A1이고, 그 오른쪽 칸은 B1이다.

킹은 다음과 같이 움직일 수 있다.

  • R : 한 칸 오른쪽으로
  • L : 한 칸 왼쪽으로
  • B : 한 칸 아래로
  • T : 한 칸 위로
  • RT : 오른쪽 위 대각선으로
  • LT : 왼쪽 위 대각선으로
  • RB : 오른쪽 아래 대각선으로
  • LB : 왼쪽 아래 대각선으로

체스판에는 돌이 하나 있는데, 돌과 같은 곳으로 이동할 때는, 돌을 킹이 움직인 방향과 같은 방향으로 한 칸 이동시킨다. 아래 그림을 참고하자.

입력으로 킹이 어떻게 움직여야 하는지 주어진다. 입력으로 주어진 대로 움직여서 킹이나 돌이 체스판 밖으로 나갈 경우에는 그 이동은 건너 뛰고 다음 이동을 한다.

킹과 돌의 마지막 위치를 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 킹의 위치, 돌의 위치, 움직이는 횟수 N이 주어진다. 둘째 줄부터 N개의 줄에는 킹이 어떻게 움직여야 하는지 주어진다. N은 50보다 작거나 같은 자연수이고, 움직이는 정보는 위에 쓰여 있는 8가지 중 하나이다.

 

출력

첫째 줄에 킹의 마지막 위치, 둘째 줄에 돌의 마지막 위치를 출력한다.

 


예제 입력 예제 출력
A1 A2 5
B
L
LB
RB
LT
A1
A2
A1 H8 1
T
A2
H8
A1 A2 1
T
A2
A3
A1 A2 2
T
R
B2
A3
A8 B7 18
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
RB
G2
H1
C1 B1 3
L
T
LB
B2
A1

풀이

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        String k = in.next();
        String d = in.next();

        int N = in.nextInt(); // 움직이는 횟수 N

        int[] king = {k.charAt(0) - 'A', k.charAt(1) - '1' + 1}; // 킹의 위치
        int[] doll = {d.charAt(0) - 'A', d.charAt(1) - '1' + 1}; // 돌의 위치

        for (int i = 0; i < N ; i++) {
            String s = in.next();

            move(s, king, doll);
        }

        print(king); // 킹의 마지막 위치 출력
        print(doll); // 돌의 마지막 위치 출력
    }

    public static void move(String s, int[] king, int[] doll) {
        String[] RLBT = {"R", "L", "B", "T", "RT", "LT", "RB", "LB"};
        int[][] m = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1}};

        int garo = 0, sero = 0;

        // 가로/세로로 어느 정도 움직여야 하는지 찾는다.
        for (int i = 0; i < 8; i++) {
            if (RLBT[i].equals(s)) {
                garo = m[i][0];
                sero = m[i][1];

                break;
            }
        }

        int kGaro = king[0] + garo;
        int kSero = king[1] + sero;

        // 킹이 움직이고서도 체스판 위에 있을 때
        if ((kGaro >= 0 && kGaro < 8) && (kSero > 0 && kSero <= 8)) {
            // 킹이 움직이는 위치에 돌이 있을 때
            if (kGaro == doll[0] && kSero == doll[1]) {
                int dGaro = doll[0] + garo;
                int dSero = doll[1] + sero;

                // 돌이 움직이고서도 체스판 위에 있을 때
                if ((dGaro >= 0 && dGaro < 8) && (dSero > 0 && dSero <= 8)) {
                    king[0] = kGaro;
                    king[1] = kSero;

                    doll[0] = dGaro;
                    doll[1] = dSero;
                }
            }
            else {
                king[0] = kGaro;
                king[1] = kSero;
            }
        }
    }

    // 출력
    public static void print(int[] arr) {
        System.out.print((char)(arr[0] + 'A'));
        System.out.println(arr[1]);
    }
}

아래에서 각 부분을 설명하겠다.

 

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        String k = in.next();
        String d = in.next();

        int N = in.nextInt(); // 움직이는 횟수 N

        int[] king = {k.charAt(0) - 'A', k.charAt(1) - '1' + 1}; // 킹의 위치
        int[] doll = {d.charAt(0) - 'A', d.charAt(1) - '1' + 1}; // 돌의 위치

        for (int i = 0; i < N ; i++) {
            String s = in.next();

            move(s, king, doll);
        }

        print(king); // 킹의 마지막 위치 출력
        print(doll); // 돌의 마지막 위치 출력
    }

일단 입력받은 킹과 돌의 가로, 세로 위치를 각각 배열에 저장했다.

원래는 체스판의 크기와 같은 크기의 배열에 킹과 돌의 위치를 표시하는 방향으로 코드를 구현하는 쪽으로 생각했다. 그러나 이 방법으로 코드를 구현하면 매번 킹을 움직일 때마다 킹과 돌의 위치를 찾아야 했다. 이걸 보완하기 위해서는 두 말의 위치를 따로 저장해두는 식으로 구현해야 하는데, 여기까지 생각이 가니 체스판과 같은 크기의 배열 없이 코드를 구현하자는 생각이 들었기에 이렇게 구현했다.

그 뒤 각 배열의 숫자는 입력받은 킹의 움직임에 맞춰 move()로 인해 바뀌게 되고, 모든 움직임이 끝나면 현재 위치를 출력하게 된다.

 

    public static void move(String s, int[] king, int[] doll) {
        String[] RLBT = {"R", "L", "B", "T", "RT", "LT", "RB", "LB"};
        int[][] m = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1}};

        int garo = 0, sero = 0;

        // 가로/세로로 어느 정도 움직여야 하는지 찾는다.
        for (int i = 0; i < 8; i++) {
            if (RLBT[i].equals(s)) {
                garo = m[i][0];
                sero = m[i][1];

                break;
            }
        }

        int kGaro = king[0] + garo;
        int kSero = king[1] + sero;

        // 킹이 움직이고서도 체스판 위에 있을 때
        if ((kGaro >= 0 && kGaro < 8) && (kSero > 0 && kSero <= 8)) {
            // 킹이 움직이는 위치에 돌이 있을 때
            if (kGaro == doll[0] && kSero == doll[1]) {
                int dGaro = doll[0] + garo;
                int dSero = doll[1] + sero;

                // 돌이 움직이고서도 체스판 위에 있을 때
                if ((dGaro >= 0 && dGaro < 8) && (dSero > 0 && dSero <= 8)) {
                    king[0] = kGaro;
                    king[1] = kSero;

                    doll[0] = dGaro;
                    doll[1] = dSero;
                }
            }
            else {
                king[0] = kGaro;
                king[1] = kSero;
            }
        }
    }

킹을 움직이고, 필요하다면 돌도 움직이는 move()함수이다. 함수의 시작 부분에 킹의 움직임에 따른 위치 변화를 배열에 미리 저장해둔 뒤 이번에 필요한 움직임에 따른 숫자를 각각 garo, sero 변수에 저장했다.

garo, sero에 저장한 숫자에 따라 이번 움직임으로 바뀌는 킹의 위치를 계산해서 kGaro, kSero에 저장했다. 그 뒤 킹이 체스판 위에 있는지, 돌이 움직여야 하는지, 움직인 돌이 체스판 위에 있는지를 확인한 뒤 이번 이동을 건너뛰지 않아도 된다면 이번 킹과 돌의 움직임 뒤의 위치를 배열에 저장했다.

 

    // 출력
    public static void print(int[] arr) {
        System.out.print((char)(arr[0] + 'A'));
        System.out.println(arr[1]);
    }

숫자로 저장되어 있는 위치 좌표를 문제의 형식에 맞게 출력해주는 함수이다.