Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

난수를 활용한 파이썬 자동 틱택토(Tic Tac Toe) 게임 구현하기

틱택토(Tic Tac Toe)는 누구나 한 번쯤 해본 간단한 게임이지만, 이번에 소개할 버전은 조금 특별합니다. 플레이어가 직접 참여하지 않아도 되는 완전 자동 게임으로, 컴퓨터가 난수를 이용해 스스로 말을 놓으며 게임을 끝까지 진행합니다.

이 구현에서는 파이썬의 두 가지 모듈인 numpyrandom을 사용합니다. 사용자에게 말을 놓을 위치를 입력받는 대신, 보드의 빈 칸 중 하나가 무작위로 선택되어 마크가 놓입니다. 승자가 결정될 때까지 매 턴이 끝날 때마다 보드 상태가 화면에 출력되며, 모든 칸이 채워졌는데도 승부가 나지 않으면 무승부로 판정해 -1을 반환합니다.

게임의 핵심 동작 방식

1. 보드 생성

my_create_board() 함수는 3×3 크기의 넘파이 배열을 만들어 모든 값을 0으로 초기화합니다. 여기서 0은 빈 칸, 1과 2는 각각 두 플레이어의 마크를 의미합니다.

2. 빈 칸 탐색과 랜덤 배치

my_possibilities() 함수는 보드에서 값이 0인 좌표를 모두 찾아 리스트로 반환하고, my_random_place() 함수는 그중 하나를 random.choice()로 골라 현재 플레이어의 마크를 놓습니다.

3. 승리 조건 판정

my_row_win(), my_col_win(), my_diag_win() 함수가 각각 가로줄, 세로줄, 대각선에 같은 마크가 세 개 이어졌는지 검사합니다. evaluate_game() 함수는 이 세 가지 조건을 종합해 승자를 판별하며, 보드가 가득 찼는데도 승자가 없다면 무승부(-1)를 반환합니다.

4. 게임 진행

my_play_game()은 실제 게임을 구동하는 메인 함수입니다. 두 플레이어가 번갈아 가며 무작위로 말을 놓고, 매 수마다 sleep(2)로 2초씩 멈추어 보드의 변화를 눈으로 확인할 수 있도록 합니다.

예제 코드

import numpy as np
import random
from time import sleep

# 먼저 비어 있는 보드를 생성합니다
def my_create_board():
    return(np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]))

# 보드에서 비어 있는 칸을 확인합니다
def my_possibilities(board):
    l = []
    for i in range(len(board)):
        for j in range(len(board)):
            if board[i][j] == 0:
                l.append((i, j))
    return(l)

# 플레이어의 말을 놓을 랜덤한 위치를 선택합니다
def my_random_place(board, my_player):
    selection = my_possibilities(board)
    current_loc = random.choice(selection)
    board[current_loc] = my_player
    return(board)

# 가로줄(row)에서의 승리 여부를 검사합니다
def my_row_win(board, my_player):
    for x in range(len(board)):
        win = True
        for y in range(len(board)):
            if board[x, y] != my_player:
                win = False
                continue
        if win == True:
            return(win)
    return(win)

# 세로줄(column)에서의 승리 여부를 검사합니다
def my_col_win(board, my_player):
    for x in range(len(board)):
        win = True
        for y in range(len(board)):
            if board[y][x] != my_player:
                win = False
                continue
        if win == True:
            return(win)
    return(win)

# 대각선에서의 승리 여부를 검사합니다
def my_diag_win(board, my_player):
    win = True
    for x in range(len(board)):
        if board[x, x] != my_player:
            win = False
    return(win)

# 게임 결과를 평가합니다
def evaluate_game(board):
    my_winner = 0
    for my_player in [1, 2]:
        if (my_row_win(board, my_player) or
            my_col_win(board, my_player) or
            my_diag_win(board, my_player)):
            my_winner = my_player
    if np.all(board != 0) and my_winner == 0:
        my_winner = -1
    return my_winner

# 게임을 시작하는 메인 함수
def my_play_game():
    board, my_winner, counter = my_create_board(), 0, 1
    print(board)
    sleep(2)
    while my_winner == 0:
        for my_player in [1, 2]:
            board = my_random_place(board, my_player)
            print(str(counter) + '번째 수 이후의 보드')
            print(board)
            sleep(2)
            counter += 1
            my_winner = evaluate_game(board)
            if my_winner != 0:
                break
    return(my_winner)

# 실행 코드
print('승자는: ' + str(my_play_game()))

실행 결과

[[0 0 0]
 [0 0 0]
 [0 0 0]]
1번째 수 이후의 보드
[[0 1 0]
 [0 0 0]
 [0 0 0]]
2번째 수 이후의 보드
[[0 1 0]
 [0 0 0]
 [0 0 2]]
3번째 수 이후의 보드
[[0 1 0]
 [0 0 0]
 [0 1 2]]
4번째 수 이후의 보드
[[0 1 0]
 [0 0 2]
 [0 1 2]]
5번째 수 이후의 보드
[[0 1 1]
 [0 0 2]
 [0 1 2]]
6번째 수 이후의 보드
[[0 1 1]
 [2 0 2]
 [0 1 2]]
7번째 수 이후의 보드
[[0 1 1]
 [2 1 2]
 [0 1 2]]
승자는: 1

난수를 기반으로 진행되기 때문에 실행할 때마다 말이 놓이는 순서가 달라지며, 게임의 흐름과 승자도 매번 바뀝니다. 위 실행 예시에서는 플레이어 1이 세로줄을 완성해 승리했습니다. 이 코드는 단순하지만, 여기에 미니맥스(minimax) 알고리즘이나 강화학습 에이전트를 추가하면 사람과 대결할 수 있는 틱택토 AI로 확장할 수 있습니다.