See if you can win at Tic Tac Toe against this formidable opponent!

# Game of tic tac toe. The nine locations on # the board are numbered 0-8 status = None game_over = False # Dictionary with keys containing the board locations (0-8) # and values are the squares at those locations squares_by_position = {} x_positions = [] o_positions = [] # The free positions on the board listed in order they should # be taken. For example, the center position (4) is listed first free_positions = [4, 0, 2, 6, 8, 1, 3, 5, 7] center_position = 4 opposite_corners = [ [0, 8], [2, 6] ] side_positions = [1, 3, 5, 7] # The positions of the 8 ways to win: three rows, three columns, and # two diagonals tic_tac_toes = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]] # Look for a case where I have two positions in a row, column, or diagonal # and the third position is free. I should select this position to win. def get_position_to_win(): for tic_tac_toe in tic_tac_toes: o_count = 0 free_count = 0 position_to_win = None for position in tic_tac_toe: if position in o_positions: o_count += 1 elif not is_taken(position): free_count += 1 position_to_win = position if o_count == 2 and free_count == 1: return position_to_win return None # Look for a case where my opponent has two positions in a row, column, # or diagonal and the third position is free. I should select this position # to block my opponent from winning. def get_position_to_block(): for tic_tac_toe in tic_tac_toes: x_count = 0 free_count = 0 position_to_block = None for position in tic_tac_toe: if position in x_positions: x_count += 1 elif not is_taken(position): free_count += 1 position_to_block = position if x_count == 2 and free_count == 1: return position_to_block # Special case: if the player has two opposite corners # and I have the center, select a side position rather # than a third corner if len(free_positions) == 6 and are_opposite_corners(x_positions) and 4 in o_positions: for side_position in side_positions: if side_position in free_positions: return side_position return None # Return true if the two positions are in opposite corners and false otherwise def are_opposite_corners(positions): if len(positions) != 2: return false; for corner_positions in opposite_corners: if positions[0] in corner_positions and positions[1] in corner_positions: return True return False # See if all the positions in a row, column, or diagonal are taken def is_tic_tac_toe(positions, tic_tac_toe): for position in tic_tac_toe: if not position in positions: return False return True # See if there is a winner based on the positions I or my opponent has def check_for_winner(positions): if len(positions) < 3: return False for tic_tac_toe in tic_tac_toes: if is_tic_tac_toe(positions, tic_tac_toe): # Draw a red line from the starting to ending position of the tic tac toe square0 = squares_by_position[tic_tac_toe[0]] square2 = squares_by_position[tic_tac_toe[2]] sprite = codesters.Line(square0.get_x(), square0.get_y(), square2.get_x(), square2.get_y(), "red") return True return False # Return true if a position is take and false otherwise def is_taken(position): return not position in free_positions # Briefly display a message above the board to the player def set_status(text, wait_time=2, color="blue"): global status if not status is None: status.hide() status = codesters.Text(text, 0, 200, color) stage.wait(wait_time) status.hide() # Process player clicks def click(sprite): global your_turn, game_over # Check if the game is already over if game_over: set_status("Hey, the game is already over!", color="red") return position = sprite.position # See if the position is already taken if is_taken(position): set_status("Hey, that position is already taken!", color="red") return # Put an X in the postion the player clicked on x_positions.append(position) free_positions.remove(position) squares_by_position[position].text.set_text("X") # Check to see if the player won if check_for_winner(x_positions): game_over = True set_status("Congratulations, you won!") return # See if all the positions have been taken if len(free_positions) == 0: game_over = True set_status("Cat's Game") return # Nobody has won yet. See of there's a move for me to win my_move = get_position_to_win() # If there's no move to win, see if there's a move to block the player from winning if my_move is None: my_move = get_position_to_block() # Otherwise, choose to best remaining free space on the board if my_move is None: my_move = free_positions[0] # Make my move o_positions.append(my_move) free_positions.remove(my_move) square = squares_by_position[my_move] square.text.set_text("O") # Check to see if I won if check_for_winner(o_positions): game_over = True; set_status("Hey, what do you know, I won!") # Draw the board board = codesters.Square(0, 0, 500, "white") # Draw a pair of vertical lines and a pair of horizontal lines for coordinate in [-50, 50]: codesters.Line(-150, coordinate, 150, coordinate, "blue") codesters.Line(coordinate, 150, coordinate, -150, "blue") # Create 9 squares in which to write the Xs and Os x_coordinates = [-100, 0, 100] y_coordinates = [100, 0, -100] for row in range(3): for column in range(3): square = codesters.Square(x_coordinates[column], y_coordinates[row], 97, "white") square.position = (row * 3) + column text = " " text = str(square.position) square.text = codesters.Text(" ", x_coordinates[column], y_coordinates[row], "blue") squares_by_position[square.position] = square square.event_click(click) set_status("It's your turn")
  • Run Code
  • Show Console
  • Codesters How To (opens in a new tab)