AI
algorithms
tic-tac-toe
best move
game strategy

What algorithm for a tic-tac-toe game can I use to determine the best move for the AI?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Tic-tac-toe is small enough that an AI can reason about the full game tree instead of relying on guesses. That makes it a classic example for learning adversarial search, because the "best move" is not just a locally good move, but the move that leads to the best outcome after the opponent responds optimally.

Why Minimax Fits Tic-Tac-Toe

The standard algorithm for tic-tac-toe is minimax. It works well because tic-tac-toe is:

  • turn-based
  • deterministic
  • zero-sum
  • fully observable

Those properties let the AI evaluate each legal move, assume the opponent will also play well, and choose the action with the best worst-case result.

In a minimax search:

  • the AI tries to maximize the score
  • the opponent tries to minimize the score
  • terminal boards get a fixed score

A common scoring system is:

  • '+1 for an AI win'
  • '-1 for an opponent win'
  • '0 for a draw'

Because tic-tac-toe has a tiny search space, you can often search to the end of the game without shortcuts.

A Simple Minimax Implementation

The board below uses a list of nine cells, where "X" is the AI, "O" is the human, and " " is empty.

python
1WIN_LINES = [
2    (0, 1, 2), (3, 4, 5), (6, 7, 8),
3    (0, 3, 6), (1, 4, 7), (2, 5, 8),
4    (0, 4, 8), (2, 4, 6),
5]
6
7
8def winner(board):
9    for a, b, c in WIN_LINES:
10        if board[a] != " " and board[a] == board[b] == board[c]:
11            return board[a]
12    return None
13
14
15def available_moves(board):
16    return [i for i, cell in enumerate(board) if cell == " "]
17
18
19def minimax(board, is_maximizing):
20    result = winner(board)
21    if result == "X":
22        return 1
23    if result == "O":
24        return -1
25    if not available_moves(board):
26        return 0
27
28    if is_maximizing:
29        best_score = -10
30        for move in available_moves(board):
31            board[move] = "X"
32            score = minimax(board, False)
33            board[move] = " "
34            best_score = max(best_score, score)
35        return best_score
36
37    best_score = 10
38    for move in available_moves(board):
39        board[move] = "O"
40        score = minimax(board, True)
41        board[move] = " "
42        best_score = min(best_score, score)
43    return best_score
44
45
46def best_move(board):
47    best_score = -10
48    chosen_move = None
49
50    for move in available_moves(board):
51        board[move] = "X"
52        score = minimax(board, False)
53        board[move] = " "
54
55        if score > best_score:
56            best_score = score
57            chosen_move = move
58
59    return chosen_move
60
61
62board = ["X", "O", "X",
63         " ", "O", " ",
64         " ", " ", " "]
65
66print(best_move(board))

This is enough to make an unbeatable tic-tac-toe AI. If both sides use minimax correctly, the game ends in a draw unless one player makes a mistake.

Improving Move Quality with Depth

Pure minimax often treats all wins equally. In practice, you usually want the AI to:

  • win as quickly as possible
  • delay losing as long as possible

You can do that by including search depth in the score:

  • '10 - depth for an AI win'
  • 'depth - 10 for an opponent win'
  • '0 for a draw'

That way, the AI prefers a faster checkmate-like finish and avoids a line that loses immediately when a slower loss is still possible.

python
1def minimax(board, is_maximizing, depth):
2    result = winner(board)
3    if result == "X":
4        return 10 - depth
5    if result == "O":
6        return depth - 10
7    if not available_moves(board):
8        return 0
9
10    if is_maximizing:
11        best_score = -100
12        for move in available_moves(board):
13            board[move] = "X"
14            best_score = max(best_score, minimax(board, False, depth + 1))
15            board[move] = " "
16        return best_score
17
18    best_score = 100
19    for move in available_moves(board):
20        board[move] = "O"
21        best_score = min(best_score, minimax(board, True, depth + 1))
22        board[move] = " "
23    return best_score

Alpha-Beta Pruning

For tic-tac-toe, alpha-beta pruning is not required, but it is worth learning because it is the standard optimization for minimax. It avoids exploring branches that cannot affect the final decision.

The idea is:

  • 'alpha tracks the best score the maximizing player can guarantee'
  • 'beta tracks the best score the minimizing player can guarantee'

When beta <= alpha, the remaining branch can be skipped.

That matters much more in larger games such as chess or connect four, but tic-tac-toe is a good place to understand the concept.

Common Pitfalls

One common mistake is evaluating only the immediate board and ignoring the opponent's next move. That creates a greedy AI that misses forks, blocks too late, and loses to simple traps.

Another mistake is forgetting to undo moves during recursion. If you place "X" on a board cell and do not reset it after the recursive call, later branches will evaluate a corrupted board state.

Scoring can also cause subtle bugs. If wins, losses, and draws are not handled consistently, the AI may prefer a draw over a forced win or may fail to block a loss.

Finally, do not overcomplicate tic-tac-toe with machine learning. Reinforcement learning can be a fun experiment, but minimax is the correct first tool here because the full game can be searched exactly.

Summary

  • Minimax is the standard algorithm for choosing the best tic-tac-toe move.
  • It works by assuming both players make optimal decisions.
  • Tic-tac-toe is small enough that you can search the complete game tree.
  • Depth-aware scoring helps the AI win faster and lose later.
  • Alpha-beta pruning is a useful optimization, even if tic-tac-toe does not require it.

Course illustration
Course illustration

All Rights Reserved.