[Python] Tic Tac Toe/틱택토 게임 알고리즘


Tic Tac Toe(틱택토) 게임은 3*3 형태의 판에서 두 명이서 번갈아가며 같은 모양을 가로,세로,대각선 상에 놓는 게임으로, 먼저 완성한 사람이 이기는 게임입니다.


1. 초기 맵 만들기

딕셔너리(dictionary)를 사용하여 9개의 (키,값)을 만들어주고 모든 값은 공백으로 넣어줍니다.

{1:' ', 2:' ', 3:' ' ... 8:' ', 9:' '}

#초기맵 만들기
the_board = {}
for i in range(1,10):
    the_board[i] = ' '

2. 맵 그리기

9칸으로 구분만 하면 됩니다.

 

(공백) | (공백) | (공백) |

------------------------------

(공백) | (공백) | (공백) |

------------------------------

(공백) | (공백) | (공백) |

------------------------------

#맵 그리기1
def print_board(board):
    for k,v in board.items():
        print(v, "| ", end="")
        if k % 3 == 0:
            print("\n" + "-" * 10)

(공백) | (공백) | (공백) 

------------------------------

(공백) | (공백) | (공백) 

------------------------------

(공백) | (공백) | (공백) 

#맵 그리기2
def print_board(board):
    for k,v in board.items():
        if k % 3 == 0 and k != 9:
            print("\n" + "-" * 10)
        elif k == 9:
            print()
        else:
            print(v, "| ", end="")

3. 게임종료 확인 함수

가로/세로/대각선이 같으면서 각 값이 공백이 아니면 게임을 종료합니다.

처음에 딕셔너리를 만들 때 각 값을 공백으로 설정해 놓았기 때문에 서로 같은 값이 공백인지 아닌지도 확인해주어야 합니다.

  • 가로의 경우 range(1,8,3) => 1,4,7 기준으로 i, i+1, i+2 즉, 1,2,3 / 4,5,6 / 7,8,9 의 값이 같은지 확인합니다.
  • 세로의 경우 range(1,4) => 1 2 3 기준으로 i, i+3, i+6 즉, 1,4,7 / 2,5,8 / 3,6,9 의 값이 같은지 확인합니다.
  • 대각선의 경우 1,5,9 / 3,5,7의 값이 같은지 확인합니다.
  • 공백은 가로/세로/대각선의 값이 같은지 확인한 후 첫 번째 값이 공백인지 확인하는 방식으로 구현하였습니다.
#게임종료 확인
#가로/세로/대각선이 같으면서 공백 X
def game_over(board):
    #가로
    for i in range(1,8,3):
        if board[i] == board[i+1] == board[i+2]:
            if board[i] != ' ':
                print(f'승자는 {board[i]}입니다')
                return True
    #세로
    for i in range(1,4):
        if board[i] == board[i+3] == board[i+6]: 
            if board[i] != ' ':
                print(f'승자는 {board[i]}입니다')
                return True
    #대각션
    if board[1] == board[5] == board [9]:
        if board[1] != ' ':
            print(f'승자는 {board[1]}입니다')
            return True 
    if board[3] == board[5] == board [7]:
        if board[3] != ' ':
            print(f'승자는 {board[3]}입니다')
            return True
        
    return False

4. 초기 설정

빈 맵을 먼저 출력해주고, 사용자 모양은 'O' / 컴퓨터는 'X'로 설정합니다. 초기 값은 사용자 먼저 시작하는 것으로 설정하였습니다. 그리고 컴퓨터가 랜덤으로 값을 넣어야 하기 때문에 1~9까지의 값을 담은 num_list도 만들어주었습니다. 컴퓨터는 num_list에 있는 값 중 랜덤으로 뽑아 모양('X')을 표시합니다.

#빈 맵 출력
print_board(the_board) 
#O/X
turn = 'O' 
#9번까지만 실행 가능해야하며 컴퓨터가 랜덤으로 값을 뽑기위한 리스트, 1~9까지 숫자 중 이미 사용된 숫자는 제거됨
num_list = [i for i in range(1,10)]

5. 반복문으로 게임 실행

O와 X 모양으로 나눠서 O는 사용자, X는 컴퓨터로 설정하고 구현하였습니다.

 

사용자 입력을 받는 경우

  • try~except문으로 입력값이 숫자가 아니라면 다시 입력할 수 있도록 구현
  • 정규식을 이용하여 숫자는 1~9 사이의 값이 입력되었는지 확인(re 모듈 사용)
  • 사용자 입력값 자리가 공백인지 확인

 

컴퓨터 입력을 받는 경우

  • num_list에 남아있는 값을 랜덤으로 선택하도록 구현(random 모듈 사용)

 

사용자/컴퓨터의 입력을 받으면 해당 칸에 O 또는 X 모양을 넣고, 이후에 컴퓨터가 입력할 수 없도록 num_list에서 해당 값을 제거하도록 구현하였습니다. 이어 순서를 바꾸고 게임 종료를 확인합니다. 종료가 되지 않았다면 다시 반복문을 실행합니다.

while True:
    if turn == 'O': #사용자 입력을 받는 경우
        while True:
            try: #int로 묶어서 문자가 들어오면 무조건 오류발생. 때문에 예외처리함
                print('어느 위치에 표시하시겠습니까? > ')
                space = int(input())
                break
            except:
                print("숫자를 입력해주세요.")

        #정규식 사용((1~9)사이의 숫자인지 확인), 입력된 위치가 비어있는지 확인
        if not re.match('^[1-9]{1}$', str(space)):
            print('(1~9) 숫자 중 입력해주세요.')
            continue
        if not the_board[space] == ' ':
            print('그 자리는 표시할 수 없습니다.')
            continue
    else: #랜덤으로 입력을 받는 경우, 남아있는 숫자 중 랜덤으로 선택
        print("컴퓨터의 랜덤 입력입니다.")
        space = random.choice(num_list)

    #맵에 체크표시 남기고, 해당 위치 값을 num_list에서 지우기
    the_board[space] = turn
    num_list.remove(space)
        
    #맵 그리기
    print_board(the_board)

    #순서 바꾸기
    if turn == 'O':
        turn = 'X'
    else:
        turn = 'O'

    #게임종료 확인하기
    if game_over(the_board) == True:
        print('게임이 종료되었습니다.')
        break
    else:
        if len(num_list) == 0:
            print('무승부 입니다.')
            print('게임이 종료되었습니다.')
            break

6. 전체 코드

#틱택토(Tic Tac Toe)
import re, random

#초기맵 만들기
the_board = {}
for i in range(1,10):
    the_board[i] = ' '

#맵 그리기
def print_board(board):
    for k,v in board.items():
        print(v, "| ", end="")
        if k % 3 == 0:
            print("\n" + "-" * 10)
# #맵 그리기2
# def print_board(board):
#     for k,v in board.items():
#         if k % 3 == 0 and k != 9:
#             print("\n" + "-" * 10)
#         elif k == 9:
#             print()
#         else:
#             print(v, "| ", end="")

#게임종료 확인
#가로/세로/대각선이 같으면서 공백 X
def game_over(board):
    #가로
    for i in range(1,8,3):
        if board[i] == board[i+1] == board[i+2]:
            if board[i] != ' ':
                print(f'승자는 {board[i]}입니다')
                return True
    #세로
    for i in range(1,4):
        if board[i] == board[i+3] == board[i+6]: 
            if board[i] != ' ':
                print(f'승자는 {board[i]}입니다')
                return True
    #대각션
    if board[1] == board[5] == board [9]:
        if board[1] != ' ':
            print(f'승자는 {board[1]}입니다')
            return True 
    if board[3] == board[5] == board [7]:
        if board[3] != ' ':
            print(f'승자는 {board[3]}입니다')
            return True
        
    return False

#빈 맵 출력
print_board(the_board) 
#O/X
turn = 'O' 
#9번까지만 실행 가능해야하며 컴퓨터가 랜덤으로 값을 뽑기위한 리스트, 1~9까지 숫자 중 이미 사용된 숫자는 제거됨
num_list = [i for i in range(1,10)] 

while True:
    if turn == 'O': #사용자 입력을 받는 경우
        while True:
            try: #int로 묶어서 문자가 들어오면 무조건 오류발생. 때문에 예외처리함
                print('어느 위치에 표시하시겠습니까? > ')
                space = int(input())
                break
            except:
                print("숫자를 입력해주세요.")

        #정규식 사용((1~9)사이의 숫자인지 확인), 입력된 위치가 비어있는지 확인
        if not re.match('^[1-9]{1}$', str(space)):
            print('(1~9) 숫자 중 입력해주세요.')
            continue
        if not the_board[space] == ' ':
            print('그 자리는 표시할 수 없습니다.')
            continue
    else: #랜덤으로 입력을 받는 경우, 남아있는 숫자 중 랜덤으로 선택
        print("컴퓨터의 랜덤 입력입니다.")
        space = random.choice(num_list)

    #맵에 체크표시 남기고, 해당 위치 값을 num_list에서 지우기
    the_board[space] = turn
    num_list.remove(space)
        
    #맵 그리기
    print_board(the_board)

    #순서 바꾸기
    if turn == 'O':
        turn = 'X'
    else:
        turn = 'O'

    #게임종료 확인하기
    if game_over(the_board) == True:
        print('게임이 종료되었습니다.')
        break
    else:
        if len(num_list) == 0:
            print('무승부 입니다.')
            print('게임이 종료되었습니다.')
            break