tic-tac-toe(오목 말고 삼목) 만들기
[step 1] player 객체 선언과 TicTacToe 객체 선언
# player.py
import math
import random
class Player():
def __init__(self, letter):
self.letter = letter
def get_move(self, game):
pass
class RandomComputerPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self, game):
pass
class HumanPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self, game):
pass
# game.py
class TicTacToe():
def __init__(self):
self.board = self.make_board()
self.current_winner = None
@staticmethod
def make_board():
return [' ' for _ in range(9)]
def print_board(self):
for row in [self.board[i*3:(i+1) * 3] for i in range(3)]:
print('| ' + ' | '.join(row) + ' |')
@staticmethod
def print_board_nums():
# 0 | 1 | 2
number_board = [[str(i) for i in range(j*3, (j+1)*3)] for j in range(3)]
for row in number_board:
print('| ' + ' | '.join(row) + ' |')
[step 1-easy] TicTacToe 쉬운 버전
# easy 1
class TicTacToe():
def __init__(self):
self.board = [' ',' ',' ',' ',' ',' ',' ',' ',' ']
self.current_winner = None
def print_board(self):
row_init = [self.board[0:3]]
# print(row_init)
for row in row_init:
print('| ' + ' | '.join(row) + ' |')
row_init = [self.board[3:6]]
for row in row_init:
print('| ' + ' | '.join(row) + ' |')
row_init = [self.board[6:9]]
for row in row_init:
print('| ' + ' | '.join(row) + ' |')
# esay 2
class TicTacToe():
def __init__(self):
self.board = [' ',' ',' ',' ',' ',' ',' ',' ',' ']
self.current_winner = None
def print_board(self):
i=0
for row in [self.board[i:i+3]]:
print('| ' + ' | '.join(row) + ' |')
i=i+3
for row in [self.board[i:i+3]]:
print('| ' + ' | '.join(row) + ' |')
i=i+3
for row in [self.board[i:i+3]]:
print('| ' + ' | '.join(row) + ' |')
i=i+3
# esay 3
class TicTacToe():
def __init__(self):
self.board = [' ',' ',' ',' ',' ',' ',' ',' ',' ']
self.current_winner = None
def print_board(self):
i=0
for row in [self.board[i:i+3] for i in range(3)]:
print('| ' + ' | '.join(row) + ' |')
i=i+3
[step 1-check] TicTacToe 의 method 동작 확인
# game.py 에 이어서
TTT=TicTacToe()
TTT.print_board()
print()
TTT.print_board_nums()
#실행결과
| | | |
| | | |
| | | |
| 0 | 1 | 2 |
| 3 | 4 | 5 |
| 6 | 7 | 8 |
[step 2] 각 player 의 착수 구역 get_move() 구현하기
# game.py
class TicTacToe():
...
def available_moves(self):
return [i for i, x in enumerate(self.board) if x == " "]
# >>> t = [1, 5, 7, 33, 39, 52]
# >>> for p in enumerate(t):
# ... print(p)
# ...
# (0, 1)
# (1, 5)
# (2, 7)
# (3, 33)
# (4, 39)
# (5, 52)
# >>> for i, v in enumerate(t):
# ... print("index : {}, value: {}".format(i,v))
# ...
# index : 0, value: 1
# index : 1, value: 5
# index : 2, value: 7
# index : 3, value: 33
# index : 4, value: 39
# index : 5, value: 52
# player.py
class RandomComputerPlayer(Player):
...
def get_move(self, game):
box = random.choice(game.available_moves())
return box
class HumanPlayer(Player):
...
def get_move(self, game):
valid_box = False
value = None
while not valid_box:
box = input(self.letter + '\'s turn. Input move (0-9): ')
try:
value = int(box)
if value not in game.available_moves():
raise ValueError
valid_box = True
except ValueError:
print('Invalid box. Try again.')
return value
[step 3] game.py 에 play 함수 구현, TicTacToe 클래스에 empty_box 관련 함수 구현
# game.py
class TicTacToe():
...
def empty_box(self):
return ' ' in self.board # return true or false
def num_empty_box(self):
return self.board.count(' ')
def play(game, x_player, o_player, print_game=True):
if print_game:
game.print_board_nums()
letter = 'X' # first turn letter
while game.empty_box():
pass # todo
# game.py 에서 동작확인
...
TTT=TicTacToe()
print(TTT.empty_box())
print(TTT.num_empty_box())
# Terminal
True
9
[step 4] game.py 의 play 함수 추가 구현, TicTacToe 클래스에 make_move 함수 구현
# game.py
def play(game, x_player, o_player, print_game=True):
...
while game.empty_box():
if letter == 'O':
box = o_player.get_move(game)
else:
box = x_player.get_move(game)
if game.make_move(box, letter):
if print_game:
print(letter + ' makes a move to box {}'.format(box))
game.print_board()
print('')
letter = 'O' if letter == 'X' else 'X' # switches player
# game.py
class TicTacToe():
...
def make_move(self, box, letter):
if self.board[box] == ' ':
self.board[box] = letter
return True
return False
[step 5] winner 관련 추가 구현
# game.py
class TicTacToe():
...
def make_move(self, box, letter):
if self.board[box] == ' ':
self.board[box] = letter
if self.winner(box, letter): # todo
self.current_winner = letter
return True
return False
...
def play(game, x_player, o_player, print_game=True):
...
while game.empty_box():
if letter == 'O':
box = o_player.get_move(game)
else:
box = x_player.get_move(game)
if game.make_move(box, letter):
if print_game:
print(letter + ' makes a move to box {}'.format(box))
game.print_board()
print('')
if game.current_winner:
if print_game:
print(letter + ' wins!')
return letter # ends the loop and exits the game
letter = 'O' if letter == 'X' else 'X' # switches player
if print_game:
print('It\'s a tie!')
[step 6] win 판정 세부 로직 구현
# game.py
import math
class TicTacToe():
...
def winner(self, box, letter):
# check the row
row_index = math.floor(box / 3)
# math.florr : Round numbers down to the nearest integer
# print(math.floor(0.6)) -> 0
# print(math.floor(1.4)) -> 1
row = self.board[row_index*3:(row_index+1)*3]
if all([s == letter for s in row]):
return True
col_index = box % 3
column = [self.board[col_index+i*3] for i in range(3)]
if all([s == letter for s in column]):
return True
if box % 2 == 0:
diagonal1 = [self.board[i] for i in [0, 4, 8]]
if all([s == letter for s in diagonal1]):
return True
diagonal2 = [self.board[i] for i in [2, 4, 6]]
if all([s == letter for s in diagonal2]):
return True
return False
[step 7] main 실행 구현
# game.py
import math
from player import HumanPlayer, RandomComputerPlayer
...
if __name__ == '__main__':
x_player = HumanPlayer('X')
o_player = RandomComputerPlayer('O')
t = TicTacToe()
play(t, x_player, o_player, print_game=True)
[step 8 & final] 실행 지연 추가
# game.py
import time
...
def play(game, x_player, o_player, print_game=True):
...
while game.empty_box():
...
letter = 'O' if letter == 'X' else 'X' # switches player
time.sleep(.8)
...
[참고자료]
https://mingrammer.com/underscore-in-python/
파이썬 언더스코어(_)에 대하여
파이썬에서 언더스코어(underscore, _)는 특별하다. 타 언어에서 언더스코어(_)는 단지 스네이크 표기법의 변수나 함수명을 위해서만 사용되어지
mingrammer.com
https://blockdmask.tistory.com/468
[python] 파이썬 join 함수 정리 및 예제 (문자열 합치기)
안녕하세요. BlockDMask입니다. 오늘은 파이썬에서 리스트를 문자열로 일정하게 합쳐주는 join 함수에 대해서 알아보려고 합니다. join 함수는 문자열을 다룰 때 유용하게 사용할 수 있는 함수이니
blockdmask.tistory.com
https://www.daleseo.com/python-class-methods-vs-static-methods/
[파이썬] 정적(static) 메서드와 클래스(class) 메서드
Engineering Blog by Dale Seo
www.daleseo.com
https://devpouch.tistory.com/74
[Python] 파이썬 enumerate 함수 사용법/예제
enumerate함수 반복문을 사용할때 리스트의 순서값, 즉 인덱스의 정보가 필요한 경우가 있습니다. enumerate함수는 리스트의 원소에 순서값을 부여해주는 함수입니다. 사용 예제는 아래와 같습니다.
devpouch.tistory.com
https://www.youtube.com/watch?v=8ext9G7xspg&t=2153s
https://github.com/kying18/tic-tac-toe
GitHub - kying18/tic-tac-toe: Tic-tac-toe AI using minimax
Tic-tac-toe AI using minimax. Contribute to kying18/tic-tac-toe development by creating an account on GitHub.
github.com