Python/파이썬 자료구조 알고리듬
[Python] Tic-Tac-Toe: Minimax algorithm
컴닥
2020. 11. 20. 20:36
반응형
틱-택-토
틱택토는 3*3 보드 위에 3칸 1줄(가로, 세로, 대각선 중 하나)을 먼저 완성하는 쪽이 이기는 보드게임입니다.
따라서 모든 경우의 수는 9! = 362_880
이 정도라면 가지치기를 하지 않고 퓨어한 미니 맥스 알고리듬으로 돌릴 수 있습니다.
*막대기게임처럼 max에서 score==1, min에서 score==-1을 찾으면 break 했습니다.
이것만 하더라도 반응 속도가 상당히 빨라집니다.
game_board: str = '_' * 9
AI = True
HUMAN = False
AI_MARK = 'X'
HUMAN_MARK = 'O'
def main():
player: bool = AI
# player: bool = HUMAN
print('initializing ...')
if player == HUMAN:
print("\nBRD KEY\n___ 789\n___ 456\n___ 123")
while find_empty(game_board) and not is_end(game_board):
if player == AI:
position, _ = minimax(game_board, 9, AI)
place(position, AI_MARK)
player = HUMAN
else:
position = input_num()
place(position, HUMAN_MARK)
player = AI
draw()
ending()
def find_empty(board: str) -> tuple[int, ...]:
return tuple(x for x, cell in enumerate(board) if cell == '_')
def is_end(board: str) -> bool:
return is_win(board, AI_MARK) or is_win(board, HUMAN_MARK)
def is_win(board, player):
for (x, y, z) in ((0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)):
if board[x] == board[y] == board[z]:
if board[x] == player:
return True
return False
def minimax(board: str, depth: int, max_player: bool) -> tuple:
position = -1
if depth == 0 or not find_empty(board) or is_end(board):
return -1, evaluate(board)
if max_player == AI:
value = float('-inf')
for each in find_empty(board):
_, score = minimax(board[:each] + AI_MARK + board[each + 1:], depth - 1, HUMAN)
if score > value:
value = score
position = each
if score == 1:
break
else:
value = float('inf')
for each in find_empty(board):
_, score = minimax(board[:each] + HUMAN_MARK + board[each + 1:], depth - 1, AI)
if score < value:
value = score
position = each
if score == -1:
break
return position, value
def evaluate(board: str) -> int:
if is_win(board, AI_MARK):
score = 1
elif is_win(board, HUMAN_MARK):
score = -1
else:
score = 0
return score
def place(x: int, player: str) -> bool:
if is_valid(x):
global game_board
game_board = game_board[:x] + player + game_board[x + 1:]
return True
return False
def is_valid(x: int) -> bool:
return x in find_empty(game_board)
def input_num() -> int:
num = -1
while num not in find_empty(game_board):
input_str = ''
while not input_str.isdecimal():
input_str = input('\n1~9?')
num = int(input_str) - 1
return num
def draw():
print(f'\nBRD KEY\n{game_board[6:]} 789\n{game_board[3:6]} 456\n{game_board[:3]} 123')
def ending():
if is_win(game_board, AI_MARK):
print('AI Win')
elif is_win(game_board, HUMAN_MARK):
print('HUMAN Win')
else:
print('Tie')
if __name__ == '__main__':
main()
initializing ...
BRD KEY
___ 789
___ 456
X__ 123
1~9?5
BRD KEY
___ 789
_O_ 456
X__ 123
BRD KEY
___ 789
_O_ 456
XX_ 123
1~9?3
BRD KEY
___ 789
_O_ 456
XXO 123
BRD KEY
X__ 789
_O_ 456
XXO 123
1~9?4
BRD KEY
X__ 789
OO_ 456
XXO 123
BRD KEY
X__ 789
OOX 456
XXO 123
1~9?9
BRD KEY
X_O 789
OOX 456
XXO 123
BRD KEY
XXO 789
OOX 456
XXO 123
Tie
반응형