Written by Mehran Sahami
This program runs a game of tic tac toe, and can even determine who wins!
Mehran made a video walking through the example. Good times:
""" File: tictactoe.py ----------------- This program allows to players to play tic-tac-toe. The board in the game is SIZE x SIZE, set using the constant SIZE. Each element on the board will contain either 'X', 'O', or None to indicate that either a particular player occupies a particular space in the grid or the space is empty (contains None). """ SIZE = 3 # The board used will be SIZE x SIZE def create_empty_board(n): """ Creates and returns a grid (list of lists), that has n rows and each row has n columns. All the elements in the grid are set to None. >>> create_empty_board(2) [[None, None], [None, None]] """ grid = [] # Create empty grid for y in range(n): # Create rows one at a time row = [] for x in range(n): # Build up each row by appending to a list row.append(None) grid.append(row) # Append the row (list) onto grid return grid def player_turn(board, symbol): """ Asks player (symbol) to make a move and records that move on the board. Players are prompted if they make an invalid move. """ valid_move = False while not valid_move: print(symbol + "'s move") row = int(input("Row: ")) col = int(input("Col: ")) # Make sure the move is in empty space and is on the board. if row < 0 or row >= SIZE \ or col < 0 or col >= SIZE \ or board[row][col]: print("Invalid move. Try again.") else: board[row][col] = symbol # Record a valid move valid_move = True def check_row(board, row): """ Checks to see if one of the players got all the spaces in a row. If so, it returns the symbol for that player. If not, it returns None. """ symbol = board[row][0] for col in range(1, SIZE): if board[row][col] != symbol: # If we find non-matching symbol then return None # their isn't a winner on this row. return symbol # Will only get here if all symbols in row match def check_column(board, col): """ Checks to see if one of the players got all the spaces in a column. If so, it returns the symbol for that player. If not, it returns None. """ symbol = board[0][col] for row in range(1, SIZE): if board[row][col] != symbol: return None return symbol # Will only get here is all symbols in column match def check_down_diagonal(board): """ Checks to see if one of the players got all the spaces in the diagonal going from top-left corner to bottom-right corner. If so, it returns the symbol for that player. If not, it returns None. """ symbol = board[0][0] for row in range(1, SIZE): if board[row][row] != symbol: return None return symbol # Will only get here is all symbols in diagonal match def check_up_diagonal(board): """ Checks to see if one of the players got all the spaces in the diagonal going from bottom-left corner to top-right corner. If so, it returns the symbol for that player. If not, it returns None. """ symbol = board[0][SIZE - 1] for row in range(1, SIZE): if board[row][SIZE - 1 - row] != symbol: return None return symbol # Will only get here is all symbols in diagonal match def check_winner(board): """ Checks to see if one of the players got three in a row by checking all the rows, columns, and two diagonals on the board. If a player got three in a row, return the symbol for that player. If not, return None. """ # Check rows for row in range(SIZE): winner = check_row(board, row) if winner: return winner # Check columns for col in range(SIZE): winner = check_column(board, col) if winner: return winner # Check diagonals winner = check_down_diagonal(board) if winner: return winner winner = check_up_diagonal(board) return winner # This could be None if last check didn't find a winner def flip_turn(symbol): """ Flips the player (symbol) whose turn it is. """ if symbol == 'X': return 'O' else: return 'X' def print_row_separator(columns): """ Prints a row separator line for the board. For example, if columns is 3, it will print: --+---+-- """ print("--+", end="") for i in range(1, columns - 1): print("---+", end="") print("--") def print_board(board): """ Prints out tic-tac-board board """ rows = len(board) # Could have used SIZE, but wanted cols = len(board[0]) # to show a different way to do this. for y in range(rows): for x in range(cols): symbol = board[y][x] if not symbol: # Print a space if symbol is None symbol = " " print(symbol, end="") if x < SIZE - 1: # Print column separator if not at end of line print(" | ", end="") else: print("") # Print "new line" at end of line if y < SIZE - 1: # Print row separator if not at end of grid print_row_separator(cols) def main(): """ Play a two-player game of tic-tac-toe """ winner = None board = create_empty_board(SIZE) player = 'X' # Player X goes first num_moves = 0 while winner == None: # Take turns until we have winner print_board(board) player_turn(board, player) num_moves += 1 # Keep track of total moves made winner = check_winner(board) if not winner: if num_moves == SIZE ** 2: # If all spaces on board are filled winner = "No one" # then there is no winner. player = flip_turn(player) print_board(board) print(winner + " won!") if __name__ == '__main__': main()