from player import RandomComputerPlayer, HumanPlayer
import time
class TicTacToe:
def __init__(self):
self.board = [' ' for _ in range(9)] # we'll use a single list to represent 3x3 board
self.current_winner = None # keep track of winner
def print_board(self):
# get the rows
for row in [self.board[i*3:(i+1)*3] for i in range(3)]: # 0,1,2 3,4,5 6,7,8
print('|' + ' | '.join(row) + '|')
@staticmethod
def print_board_nums():
# it's going to print 0 | 1 | 2 , etc (tell us what number corresponds to what position)
number_board = [[str(i) for i in range(j*3, (j+1)*3)] for j in range(3)] # [ [0,1,2],[3,4,5],[6,7,8] ]
for row in number_board:
print('|' + ' | '.join(row) + '|')
def available_moves(self):
# it'll return []
moves = []
for (i,spot) in enumerate(self.board):
# ['x', 'x', 'o'] -> [(0, 'x'), (1, 'x'), (2, 'o')]
if spot ==' ':
moves.append(i)
return moves
# You can also use this:
# return [i for i, spot in enumerate(self.board) if spot == ' ']
def empty_squares(self):
return ' ' in self.board
def num_empty_squares(self):
return self.board.count(' ')
def make_move(self, square, letter):
# If valid move, them make the move (assign square to letter)
# then return True. If invalid, then return False.
if self.board[square] ==' ':
self.board[square] = letter
if self.winner(square, letter):
self.current_winner = letter
return True
return False
def winner(self, square, letter):
# wins if 3 in a row anythere. We have to check all of these
# first we check the row
row_ind = square // 3
row = self.board[row_ind*3 : (row_ind+1)*3]
if all([spot == letter for spot in row]):
return True
# check column
col_ind = square % 3
column = [self.board[col_ind+i*3] for i in range(3)]
if all([spot == letter for spot in column]):
return True
# check diagonals
# but if the square is an even umber(0, 2, 4, 6, 8)
# these are the only moves possible to win a diagonal
if square % 2 == 0:
diagonal1 = [self.board[i] for i in [0, 4, 8]] # left to right diagonal
if all([spot == letter for spot in diagonal1]):
return True
diagonal2 = [self.board[i] for i in [2, 4, 6]] # right to left diagonal
if all([spot == letter for spot in diagonal2]):
return True
# If all of them fail
return False
def play(game, x_player, o_player, print_game = True):
# return the winner of the game(the letter)! or None for a tie
if print_game:
game.print_board_nums()
letter = 'X' #starting letter
# iterate while the game still has empty squares
#(we don't have to worry about winner because we'll just return that
# which breaks the loop)
while game.empty_squares():
# get the move from the appropriate player
if letter == 'O':
square = o_player.get_move(game)
else:
square = x_player.get_move(game)
if game.make_move(square, letter):
print(letter + f' makes a move to square {square}')
game.print_board()
print('') # just empty line
if game.current_winner != None:
if print_game:
print(letter + ' wins!')
return letter
# switch player
if letter == 'X':
letter = 'O'
else:
letter = 'X'
# or you can also use this
# letter = 'O' if letter =='X' else 'X'
# add a tiny pause
time.sleep(0.8)
if print_game:
print('It\'s a tie!')
if __name__ == '__main__':
x_player = HumanPlayer('x')
o_player = RandomComputerPlayer('o')
# o_player = HumanPlayer('o')
t = TicTacToe()
play(t, x_player, o_player, print_game=True)
import random
class Player:
def __init__(self, letter):
# letter is x or o
self.letter = letter
# we want all players to get their next move
def get_move(self, game):
pass
class RandomComputerPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self, game):
# get a random valid spot for our next move
square = random.choice(game.available_moves())
return square
class HumanPlayer(Player):
def __init__(self, letter):
super().__init__(letter)
def get_move(self, game):
valid_square = False
val = None
while not valid_square:
square = input(self.letter + '\'s turn. Input move(0-8): ')
# we're going to check that this is a correct value by tring cast
#it to an integer, and if it's not, then we say it's invalid.
# If that spot is not available on the board, we also say it's invalid.
# try and except can deal with specific errors that happen.
# Right here we use them to fix ValueError problems caused by square and val
try:
val = int(square)
if val not in game.available_moves():
raise ValueError
valid_square = True # If these are successful, then hurray!
except ValueError:
print('Invalid square. Try again.')
return val
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up