강의로 돌아가기
송민기

Python 정답 코드

게임 이론 알고리즘 문제를 코딩테스트에서 접한 것은 처음이라 많이 헤맸습니다.
두서 없이 코드를 작성했지만 다른 분들에게도 도움이 됐으면 좋겠다고 생각해 올립니다.

기본 전략은 모든 경우를 탐색하는 완전 탐색을 dfs로 구현하는 것입니다.
이 때 dfs의 반환 값은 (a의 승리 여부 boolean, 해당 경로의 길이)로 2가지 값을 tuple로 반환합니다.
두 사람이 번갈아서 turn을 진행하므로 turn을 매개변수로 사용하면 어떤 캐릭터가 움직일 차례인지 알 수 있습니다.
turn % 2 == 0이면 A가 움직일 차례, 그 외는 B가 움직일 차례로 생각했습니다.

승패가 결정되는 경우는 두 가지로
1) 현재 차례의 캐릭터가 움직일 수 없는 경우
2) 두 캐릭터가 같은 위치에 있어서 한 캐릭터가 이동하면 다른 캐릭터가 탈락하는 경우
로 나눌 수 있습니다.

두 가지의 승패 처리 로직을 따로 생각해야 합니다.

board의 복사를 막기 위해 back-tracking을 사용했습니다.

작성중인 코드―solution.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def get_next_positions(board, loc):  # 현재 위치(loc)에서 다음으로 이동 가능한 위치를 반환한다.
    dRow, dCol = [0, 0, 1, -1], [1, -1, 0, 0]
    next_positions = []
    for d in range(4):
        nr, nc = loc[0] + dRow[d], loc[1] + dCol[d]
        if nr < 0 or nc < 0 or nr >= len(board) or nc >= len(board[0]):
            continue
        elif board[nr][nc] == 0:
            continue
        next_positions.append((nr, nc))
    return next_positions


def search(board, aloc, bloc, turn):  # dfs
    if turn % 2 == 0:
        next_positions = get_next_positions(board, aloc)
    else:
        next_positions = get_next_positions(board, bloc)
    if not next_positions:  # 현재 turn의 캐릭터가 이동할 수 없는 경우로 현재 turn의 캐릭터가 패배한다.
        return turn % 2 != 0, turn  # ((A가 이긴다면 True, B가 이긴다면 False), 현재까지 이동한 횟수)

    if aloc == bloc:  # 현재 캐릭터가 이동할 수 있으면서 aloc == bloc이면 현재 turn의 캐릭터가 승리한다.
        return turn % 2 == 0, turn + 1

    win, lose = [], []
    if turn % 2 == 0:
        board[aloc[0]][aloc[1]] = 0  # 캐릭터가 이동하면 기존의 자리는 0으로 처리한다.
        for nr, nc in next_positions:
            is_a_win, cnt = search(board, [nr, nc], bloc, turn + 1)
            if is_a_win:
                win.append(cnt)
            else:
                lose.append(cnt)
        board[aloc[0]][aloc[1]] = 1  # 백트래킹
    else:
        board[bloc[0]][bloc[1]] = 0
        for nr, nc in next_positions:
            is_a_win, cnt = search(board, aloc, [nr, nc], turn + 1)
            if not is_a_win:
                win.append(cnt)
            else:
                lose.append(cnt)
        board[bloc[0]][bloc[1]] = 1

    if win:                             # 승리하는 경우가 하나라도 있으면 
        return turn % 2 == 0, min(win)  # 승리하는 사람과 가장 빨리 승리하는 경우를 반환한다.
    else:                               # 승리하는 경우가 하나도 없으면
        return turn % 2 != 0, max(lose) # 패배하는 가장 긴 루트를 반환한다.


def solution(board, aloc, bloc):
    winner, answer = search(board, aloc, bloc, 0)
    return answer
  • 김록원

    카카오 해설과 함께 이 코드를 보니 완벽히 이해가 갑니다! 감사합니다!

    김록원―2023.04.12 19:29
0 개의 답변
답변 쓰기
이 입력폼은 마크다운 문법을 지원합니다. 마크다운 가이드 를 참고하세요.