Watch a Game AI Think: Minimax and Alpha-Beta, Live

Our Tic-Tac-Toe, Connect 4, Checkers, Othello and Chess opponents all run the same idea: search the game tree, assume the opponent plays their best, and pick the move with the best guaranteed outcome. That idea is minimax, and alpha-beta pruning is what makes it fast. Below you can step through both on a real board and watch the second one skip work the first one wastes.

 ·  Updated September 2026

Squares are positions; the top square is the AI to move (a MAX layer), the next is your reply (a MIN layer), and so on. Leaves score +1 (AI wins), −1 (you win) or 0 (draw). Step to watch each layer take the best (max) or worst-for-the-AI (min) of its children. Turn on alpha-beta and the grayed branches are the ones it proves it can skip — same move, fewer nodes.

The whole algorithm, in two functions

Minimax is the tree walk you just watched. Alpha-beta is the same walk plus two running bounds — alpha (the best MAX can already guarantee) and beta (the best MIN can already guarantee) — that let it stop exploring a branch the moment it cannot change the decision.

Minimax
function minimax(node, isMax):
  if node is terminal:
    return score(node)          # +1 / -1 / 0
  if isMax:
    best = -inf
    for child in node.moves:    # AI's turn
      best = max(best, minimax(child, false))
    return best
  else:
    best = +inf
    for child in node.moves:    # your turn
      best = min(best, minimax(child, true))
    return best
Alpha-beta pruning
function ab(node, alpha, beta, isMax):
  if node is terminal:
    return score(node)
  if isMax:
    best = -inf
    for child in node.moves:
      best = max(best, ab(child, alpha, beta, false))
      alpha = max(alpha, best)
      if beta <= alpha: break   # prune rest
    return best
  else:
    best = +inf
    for child in node.moves:
      best = min(best, ab(child, alpha, beta, true))
      beta = min(beta, best)
      if beta <= alpha: break   # prune rest
    return best

Same answer, provably — pruning never changes the value at the root, only how many nodes you touch to find it. On full-depth Tic-Tac-Toe that's a 93% cut (549,945 → 36,528 nodes, ~0.3 ms).

Nodes searched — full-depth Tic-Tac-Toe Minimax 549,945 nodes Alpha–beta 36,528 nodes (−93%) lkforge.com
Same move, same guaranteed value — alpha-beta just proves it can skip 93% of the branches.

Why "just search deeper" gets expensive fast

A search that looks d moves ahead visits roughly bd nodes, where b is the branching factor — how many moves you typically have. Drag the depth and switch games to feel it. (Branching factors are approximate published averages, for illustration.)

That growth is exactly why alpha-beta and the tricks in our real engines matter — and why a deeper search is not always a better one: a shallow tic-tac-toe search still lost 2 of 200 games.

The same idea, five different games

Every opponent on the site is this algorithm with a different board, a different way of scoring a position, and different tricks to search deeper without searching everything.

GameBoardBranching (approx.)How it scores a positionSearch tricks
Tic-Tac-Toe3×3≤ 9 (~4) Win / lose / draw — solved exactly at full depth Minimax + alpha-beta, full depth on 3×3 Play →
Connect 47×6≤ 7 (~4) Threats, central control, connected pieces Bitboard negamax + alpha-beta + transposition table + iterative deepening Play →
Checkers8×8~2.8 Material, kings, position Iterative-deepening negamax + alpha-beta + capture quiescence Play →
Othello8×8~10 Corners, mobility, positional square weights Iterative-deepening negamax + alpha-beta + exact endgame solve Play →
Chess8×8~35 Material, king safety, pawn structure, open files Negamax + alpha-beta + null-move + quiescence + check extensions + move ordering Play →

Read the actual code

The pseudocode above is the shape; here is a real, unminified engine that runs one of these opponents in your browser — iterative-deepening negamax with alpha-beta pruning and capture-aware quiescence, about 230 lines of vanilla JavaScript: the LK Forge checkers engine on GitHub Gist.

And you don't have to take the node counts on faith. This self-contained script runs plain minimax and alpha-beta over the exact Tic-Tac-Toe position above and prints the counts — 14 nodes down to 10 with pruning — with no dependencies: node reproduce-minimax.mjs.

Read the rest of the cluster

Common questions

What is minimax?

A decision rule for two-player games: search the game tree, assume the opponent always plays their best reply, and pick the move with the best guaranteed outcome. LK Forge's Tic-Tac-Toe, Connect 4, Checkers, Othello and Chess opponents all use it.

What does alpha-beta pruning do?

It skips branches that provably cannot change the result, so it returns the same move and the same guaranteed value as plain minimax while visiting far fewer positions. On full-depth Tic-Tac-Toe that is a 93% cut — 549,945 nodes down to 36,528, in about 0.3 ms.

Does alpha-beta ever change the move minimax would pick?

No. It is an exact optimization — same optimal move, same value. It only proves that certain branches cannot affect the outcome and so can be ignored.

Why is full-depth search not used on every game?

Because the tree grows exponentially with the branching factor. Tic-Tac-Toe (about 4) is solvable at full depth, but Othello (about 10) and Chess (about 35) explode, so the real engines add depth caps and other search tricks on top of alpha-beta.

Is Tic-Tac-Toe with minimax beatable?

No. A minimax player never chooses a move that leads to a loss, so its worst case is a draw. That is why you cannot beat the LK Forge Tic-Tac-Toe AI at full depth — the best you can force is a tie.

Can I reproduce the node counts?

Yes. A self-contained script with no dependencies runs plain minimax and alpha-beta over the teaching position and prints the counts (14 nodes down to 10), and the full-depth 549,945 to 36,528 figures come from the same method.

Share this X Facebook Reddit