Dev Diary

[백준] 1063 킹 본문

Algorithms

[백준] 1063 킹

sik9252 2023. 5. 21. 22:22
SMALL

백준 1063 킹 문제 바로가기

문제 이해하기

핵심 1: 킹과 돌 2개의 물체가 있다.

핵심 2: 아래와 같은 명령으로 킹의 움직임을 제어할 수 있다.

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

핵심 3: 주어진 명령을 이용해 킹을 움직이다가 체스판 위에 놓여있는 돌과 같은 위치에 놓이게 된다면(겹쳐진다면) 방금 킹이 이동했던 방향으로 돌도 이동시킨다.

핵심 4: 킹과 돌 모두 체스판 범위인 8x8을 벗어나게 되는 상황이 발생한다면, 해당 상황을 발생하게한 이동을 무르고 건너뛴다.

내가 문제를 읽으며 중요하다고 생각한 부분은 이정도였고, 이 중에서도 핵심 3과 4를 신경써가며 구현해야겠다는 생각을 했다.


풀이

실패한 코드 보기
import sys
input=sys.stdin.readline

x = [1, -1, 0, 0, 1, -1, 1, -1]
y = [0, 0, -1, 1, 1, 1, -1, -1]
ctrl = ['R', 'L', 'B', 'T', 'RT', 'LT', 'RB', 'LB']

pos_king, pos_stone, N = map(str, input().split())

pos_king_x = ord(pos_king[0])
pos_king_y = int(pos_king[1])
pos_stone_x = ord(pos_stone[0])
pos_stone_y = int(pos_stone[1])

for _ in range(int(N)):
    move = ctrl.index(input().rstrip())

    check_king_x = pos_king_x + x[move]
    check_king_y = pos_king_y + y[move]

    if check_king_x < 65 or check_king_x > 72 or check_king_y < 1 or check_king_y > 8:
        continue

    # 여기가 문제였다! 모서리에만 집중했다 그러면 안되는데
    if check_king_x == pos_stone_x and check_king_y and pos_stone_y:
        if (pos_stone_x==65 or pos_stone_x==72) and (pos_stone_y==1 or pos_stone_y==8):
            continue

    pos_king_x = check_king_x
    pos_king_y = check_king_y

    if pos_king_x == pos_stone_x and pos_king_y == pos_stone_y:
        check_stone_x = pos_stone_x + x[move]
        check_stone_y = pos_stone_y + y[move]

        if check_stone_x < 65 or check_stone_x > 72 or check_stone_y < 1 or check_stone_y > 8:
            continue

        pos_stone_x = check_stone_x
        pos_stone_y = check_stone_y

print(chr(pos_king_x) + str(pos_king_y), chr(pos_stone_x) + str(pos_stone_y), sep='\n')

 

성공한 코드

import sys
input=sys.stdin.readline

# 이동 가능한 위치와 명령을 각각 x, y, ctrl 배열에 저장해둔다
# 만약 'B'를 입력받으면 B는 index 2에 있으므로 x, y배열에서 index 2에 해당하는
# x=0, y=-1이 수행되어 아래로 이동하게 된다
x = [1, -1, 0, 0, 1, -1, 1, -1]
y = [0, 0, -1, 1, 1, 1, -1, -1]
ctrl = ['R', 'L', 'B', 'T', 'RT', 'LT', 'RB', 'LB']

pos_king, pos_stone, N = map(str, input().split())

# 편리한 계산을 위해 입력받은 알파벳을 아스키코드를 이용해 숫자로 변환한다
pos_king_x = ord(pos_king[0])
pos_king_y = int(pos_king[1])
pos_stone_x = ord(pos_stone[0])
pos_stone_y = int(pos_stone[1])

for _ in range(int(N)):
    # 입력받은 명령의 index를 가져옴
    move = ctrl.index(input().rstrip())

    # 이동 가능한 위치인지 검사하기 위해 킹의 이동을 새로운 변수에 저장한다
    check_king_x = pos_king_x + x[move]
    check_king_y = pos_king_y + y[move]

    # 킹이 체스판 범위를 넘어서는 경우인지 검사
    if check_king_x < 65 or check_king_x > 72 or check_king_y < 1 or check_king_y > 8:
        continue

    # 이동 가능한 범위였다면 실제 킹의 위치를 이동한 위치로 변경한다
    pos_king_x = check_king_x
    pos_king_y = check_king_y

    # 킹이랑 돌이 같은 위치에 서게 되는 경우
    if pos_king_x == pos_stone_x and pos_king_y == pos_stone_y:
      # 돌도 마찬가지로 이동 가능한 위치인지 검사하기 위해 돌의 이동을 새로운 변수에 저장한다
        check_stone_x = pos_stone_x + x[move]
        check_stone_y = pos_stone_y + y[move]

        # 돌이 체스판 범위를 벗어나는 경우(이동 불가능)
        if check_stone_x < 65 or check_stone_x > 72 or check_stone_y < 1 or check_stone_y > 8:
            # 킹을 이전 위치로 돌려놈 (여기가 추가한 부분)
            # 즉, 이동했던 방향의 반대로 다시 이동시킨다
            pos_king_x -=  x[move]
            pos_king_y -= y[move]
            continue

        # 이동 가능한 범위였다면 실제 돌의 위치를 이동한 위치로 변경한다
        pos_stone_x = check_stone_x
        pos_stone_y = check_stone_y

# 최종적인 킹과 돌의 위치를 출력한다
print(chr(pos_king_x) + str(pos_king_y), chr(pos_stone_x) + str(pos_stone_y), sep='\n')

정리하자면, 내가 헤맸던 곳은 돌이 체스판의 끝에 도달해 더 이상 움직일 수 없는 상태가 되었을 때, 다음 명령에서 킹이 움직일 수 없는 상태가 된 돌이 있는 자리로 이동하려고 하면 돌은 더는 이동할 수 없으므로 해당 명령은 수행될 수 없기 때문에 이것을 어떻게 처리해야하냐는 부분이였는데, 그냥 쉽게 생각해 다시 킹을 이전 위치로 되돌려 놓으면 되는 문제였다.


느낀점

아직 내 수준에서 한번 쓱 읽고 만만하게 봤던 문제였던것 같다. 특히 왠지 모르겠지만 돌이 체스판의 모서리인 A1, A8, H1, H8에 있으면서 킹이 그 옆에 딱 붙어있는 경우에만 돌도 킹도 모두 막혀서 이동할 수 없다는 생각에 틀어박혀 있던것이 이 문제에 시간을 쏟은 제일 큰 오류였다. 왜 모서리에만 그렇게 집착했을까? 돌이 A7에 있고 킹이 B7에 있는 경우에 'L' 명령을 받아도 둘 다 막혀서 이동할 수 없고 돌이 F1에 있고 킹이 E2에 있는 경우에 'RB' 명령을 받아도 둘 다 막혀서 이동할 수 없다는 것을 뒤늦게 깨달았다. (^-^)

모서리에만 집착하면서 이런 이상한 코드를 추가했는데

    if check_king_x == pos_stone_x and check_king_y and pos_stone_y:
        if (pos_stone_x==65 or pos_stone_x==72) and (pos_stone_y==1 or pos_stone_y==8):
            continue

이렇게 모서리에만 집착했던 이유가 코드를 완성했다고 생각하고 테스트 케이스를 넣었을 때 틀렸던 케이스가 모두 돌이 모서리에 있는 경우였기 때문인것 같다. 다음부터는 주어진 케이스에만 집중해서 코드를 구현하려고 하지 말고, 더욱 넓게 보는 습관을 길러야겠다.

LIST