The Tic-Tac-Toe game supports multiple game modes by combining different player types. You can configure any combination of Human, Random AI, or Genius AI players.
The Genius AI uses the minimax algorithm to evaluate all possible future game states:
player.py
def get_move(self, game): if len(game.available_moves()) == 9: # Randomly choose one square = random.choice(game.available_moves()) else: # Get the square based off the minimax algorithm square = self.minimax(game, self.letter)['position'] return square
The minimax algorithm recursively simulates all possible moves to find the optimal play:
player.py
def minimax(self, state, player): max_player = self.letter other_player = 'O' if player == 'X' else 'X' if state.current_winner == other_player: return { 'position': None, 'score': 1 * (state.num_empty_squares() + 1) if other_player == max_player else -1 * ( state.num_empty_squares() + 1) } elif not state.empty_squares(): return {'position': None, 'score': 0} if player == max_player: best = {'position': None, 'score': -math.inf} else: best = {'position': None, 'score': math.inf} for possible_move in state.available_moves(): # Step 1: make a move, try that spot state.make_move(possible_move, player) # Step 2: recurse using minimax to simulate a game after making that move sim_score = self.minimax(state, other_player) # now, we alternate players # Step 3: undo the move state.board[possible_move] = " " state.current_winner = None sim_score['position'] = possible_move # Otherwise this will get messed up from the recursion # Step 4: update the dictionaries if necessary if player == max_player: if sim_score['score'] > best['score']: best = sim_score # Replace best else: # But minimize the other player if sim_score['score'] < best['score']: best = sim_score # Replace best return best