'''An object-oriented game of Tic Tac Toe.''' EMPTY = " " # marker for an empty square SIZE = 3 # size of the game board DASHES = 7 * '-' # used in printing class Player: '''A player of the game represented as a name and a marker.''' def __init__(self, name, marker): '''Save the player name and marker symbol.''' self.name = name self.marker = marker def __str__(self): return self.name + " (" + self.marker + ")" class Move: '''A single move in the game -- i.e., a particular player playing on a particular square.''' def __init__(self, player, row, col): self.player = player self.row = row self.col = col def __str__(self): return '{0} played row {1}, col {2}'.format(self.player, self.row, self.col) class Game: '''A text-based game of Tic-Tac-Toe''' def __init__(self): '''Initialize the game board and players.''' self.board = [] for row_num in range(SIZE): board_row = [] for col_num in range(SIZE): board_row.append(EMPTY) self.board.append(board_row) def __str__(self): '''Draw the game board.''' board_str = DASHES + "\n" for row in self.board: board_str += "|" for marker in row: board_str += marker + "|" board_str += "\n" + DASHES + "\n" return board_str def read_move(self, player): '''Read in the next move for the given player''' valid_move = False while not valid_move: # read a move as row, col numbers from the user input_str = input(str(player) + ': move r, c: ') try: (play_x, play_y) = input_str.split(',') play_x = int(play_x) play_y = int(play_y) # check if this in empty square if self.board[play_x][play_y] == EMPTY: valid_move = True except: # handle the case if the rol/col numbers are invalid print("Invalid move, try again") # construct and return the move object return Move(player, play_x, play_y) def make_play(self, move): '''Update the board according to the given move.''' self.board[move.row][move.col] = move.player.marker def board_full(self): '''Return whether every square on the board is occupied.''' for row in self.board: for space in row: if space == EMPTY: return False return True def game_won(self, last_move): '''Check whether the given move won the game.''' # nothing to check on the first move if last_move == None: return False # grab the marker and square played from the last move marker = last_move.player.marker row_played = last_move.row col_played = last_move.col # check the row through row_played row_win = True for col in range(SIZE): if self.board[row_played][col] != marker: row_win = False # check the col through col_played col_win = True for row in range(SIZE): if self.board[row][col_played] != marker: col_win = False # check the right diag diag1_win = True for i in range(SIZE): if self.board[i][i] != marker: diag1_win = False # check the left diag diag2_win = True for i in range(SIZE): if self.board[i][SIZE - 1 - i] != marker: diag2_win = False # return whether any win conditions were met return row_win or col_win or diag1_win or diag2_win def main(): '''Run a game of tic tac toe.''' # construct the board and players ttt = Game() player1 = Player('Alice', 'A') player2 = Player('Bob', 'B') next_player = None last_move = None # stop reading moves once the game is over while not ttt.game_won(last_move) and not ttt.board_full(): # get the next player if next_player == player2: next_player = player1 else: next_player = player2 # print the current board print(ttt) # read a move for the next player next_move = ttt.read_move(next_player) # update the board ttt.make_play(next_move) # save the last move last_move = next_move # game over, show the final board configuration print(ttt) # check if someone won if ttt.game_won(last_move): print(next_player, 'wins!') else: print('Game ended in a draw!') main()