SYSTEMS / JUNE 2026
Tic-Tac-Toe Minimax AI
A terminal game with an AI that picks the best move by searching every outcome.
Built on my own.
- MY ROLE
- Solo project
- KEY RESULT
- Never lost in 1,200 games against a random player
Built with
- Python
- Minimax
- Recursion
What it is
This is a Tic-Tac-Toe game for the terminal, with a computer player that never loses. It decides each move by trying out every way the rest of the game could go. That method is called Minimax.
To check it works, I made it play against a computer that moves at random. Out of 1,200 games, the perfect player won 988, drew 212, and lost none.
What it can do
Three kinds of player
A human, a random player, and the perfect one. Any two can play each other.
Perfect play
The AI always picks the best move available, so the worst it can do is draw.
Faster wins
Among winning moves, it prefers the one that wins sooner.
Watch it play
A visual mode shows the board move by move, with a short pause between moves.
Run many games at once
A silent mode plays any number of games and counts the wins, losses, and draws.
How a request flows
- game.py
- player.py
- Minimax
- Simulation
How it works
- 01
For each empty square, the AI pretends to play there.
- 02
It imagines both players playing their best until the game ends.
- 03
It scores how that imagined game ends: a win is good, a loss is bad, and a draw is zero.
- 04
It undoes the pretend move and remembers the score.
- 05
Once it has tried every square, it plays the one with the best score.
Illustration
Why
Minimax is easy to describe and easy to get subtly wrong. I wanted to write the recursion myself and check it against a player that moves at random.
What I built
- 01
Wrote the board, winner detection, and game loop in game.py, and the Random, Human, and Minimax players in player.py.
- 02
Implemented the recursive Minimax search: try a move, simulate the rest of the game, undo the move, and keep the best score.
- 03
Weighted a win by the number of empty squares left, so the AI prefers winning sooner.
- 04
Added a simulation mode that runs any number of games silently and reports win, loss, and tie counts.
The code
def minimax(self, state, player):
max_player = self.letter # yourself
other_player = "O" if player == "X" else "X" # othe other player
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(): # no empty squares
return {"position": None, "score": 0}
if player == max_player:
best = {"position": None, "score": -math.inf} # each score should maximize
else:
best = {
"position": None,
"score": math.inf,
} # each score should be minimize
for possible_move in state.available_moves():
# step 1 - make a move and try that spot
state.make_move(possible_move, player)
# step 2 - use minimax to simuilate a game after making that move
sim_score = self.minimax(
state, other_player
) # now, we alternate the 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
# step 4 - update the dictionaries if necessary
if player == max_player:
if sim_score["score"] > best["score"]:
best = sim_score # replaces best
else: # minimzies the other player
if sim_score["score"] < best["score"]:
best = sim_score # replaces best
return bestSee it run
After 1200 iterations, we see 0 X wins, 988 O wins, and 212 tiesOutcome
A game you can play in the terminal. Run against a random player for 1,200 games, the Minimax player won 988 and tied 212, with no losses.
The trade-off
It searches the full game tree on every move. That is fine for a 3×3 board, but it would not scale to larger boards without something like alpha-beta pruning.
What I learned
Undoing a move correctly, including the winner flag, is as important as the scoring, because the search shares one board.
What I'd fix next
Add alpha-beta pruning and a board-size option to see where the plain search stops being practical.
Working on something like Tic-Tac-Toe Minimax AI?
Tell me what you're building and I'll reply within two business days.