CS 440 · Adversarial search · Lecture 5

Proving you don't need to look.

Minimax solves tic-tac-toe by expanding half a million positions. Alpha–beta returns the identical answer after examining a small fraction of them — not by guessing, and not by approximating, but by proving that the rest cannot matter.

The one idea

Alpha–beta never asks “does this subtree exist?”
It asks “can anything in this subtree still change my decision?”

Where we left off

The agent that never loses

It searches to the end of the game before every move, so nothing surprises it. Watch the position count under each board — that is the price of certainty, and the rest of this page is about how to stop paying it.

Agent moves first

X AgentO You

Agent
0
Draw
0
You
0

You move first

X YouO Agent

Agent
0
Draw
0
You
0

01

The explosion of possibilities

Nine choices, then eight, then seven. Each one is unremarkable. Multiply them and the futures run away from you. Add one turn at a time and watch.

Positions after each turn, if no game ended early.
Stop and think Nine cells, nine turns — so is the tree 9! = 362,880 nodes?

No, and it is bigger than that. 9! counts the orderings of nine moves, which is roughly the number of leaves in a tree where nobody ever wins early. The game tree also contains every prefix: the root, the 9 positions after one move, the 72 after two, and so on. Internal nodes are nodes too.

Pushing in the other direction, games that end in a win have no children, which removes whole branches. Both effects are real. The exact answer is below, and the exact answer is not the point — the point is that a handful of choices per turn produces a number you cannot enumerate by hand.

Nodes in the real tree
—
Of those, finished games
—
Value with perfect play
—
Time to expand
—
Full minimax, in your browser, no pruning.

02

What minimax assumes about your opponent

Before any search, a modelling decision: MAX tries to push the final number up, MIN tries to push it down, and one player's gain is exactly the other's loss. Minimax then assumes MIN plays perfectly. Not probably-well — perfectly. Everything the algorithm proves is conditional on that.

OutcomeMAX utilityMIN utility
MAX wins+1−1
Draw00
MIN wins−1+1
Aside Do the two utilities literally have to sum to zero?

No. What matters is that the players' preferences are exactly opposed. Two players splitting a fixed £100 get (k, 100 − k) — the total is always 100, a constant-sum game.

Subtract 50 from each and you get (k − 50, 50 − k), which sums to zero. Nothing about anyone's strategy changed; the numbers were relabelled. So “zero-sum” is a statement about opposed preferences, not about arithmetic. Minimax works on any constant-sum game.

Where it genuinely breaks is games that are neither — where both players can be made better off at once. Then “the opponent minimises my score” is simply false, and you need different machinery.

03

Minimax on four leaves

Small enough to do in your head. MAX moves first and picks a branch; MIN then picks a leaf. The leaf numbers are MAX's payoff.

Stop and think You looked at all four leaves. Did you have to?

Work the left branch first: MIN picks min(3, 5) = 3, so MAX can guarantee 3 by going left.

Now the right branch. Its first leaf is 2. MIN is choosing here, and MIN already has a 2 available — so the right branch is worth at most 2, whatever the fourth leaf says. MAX has 3 elsewhere. The fourth leaf cannot change the decision, so it never needs to be read.

That is the entire algorithm. Everything from here is bookkeeping for that one argument.

04

A cutoff, with no symbols at all

The same reasoning on a tree where the saving is worth having. Step through it and decide for yourself when to stop — no Greek letters until the end.

Say it without symbols

MIN can already hold branch B to 3. MAX can already get 5 elsewhere. So MAX will never walk into B — and what is underneath it stops being a question.

05

Now give the two facts names

Those two facts — what MAX can already guarantee and what MIN can already hold MAX to — get carried down the tree as a pair of numbers. That is all α and β are. They are not the algorithm; they are a compact record of what has already been proved.

α — MAX's floor
“Somewhere above here, I have already found a line worth α. I will never accept less.” Read it as guaranteed ≥ α.
β — MIN's ceiling
“Somewhere above here, I have already found a reply that holds MAX to β. I will never allow more.” Read it as allowed ≤ β.

α only ever rises

MAX has found lines worth 3, then 5, then 4, then 7, then 6. Its guarantee is the best so far — it would never trade a guaranteed 5 back for a 4.

β only ever falls

MIN has found replies holding MAX to 9, then 7, then 8, then 4, then 6. Its ceiling is the tightest so far, by exactly the same argument.

Stop and think Why does α ≥ β mean “stop”?

Unpack both sides into English. α says MAX can already guarantee at least α somewhere else. β says MIN can already hold this branch to at most β.

If α ≥ β, then the most this branch could ever deliver is no better than something MAX already has in hand. MAX is the one choosing whether to come here, and MAX has no reason to. The inequality is not the reason — it is the receipt.

06

The walkthrough, on a real position

Tic-tac-toe, searched to the end. Nodes appear only as the search reaches them, because a pruned subtree is never built — though the positions in it exist in the game all the same. Turn on Ask me before each decision and the search will stop and make you call it.

step 0 / 0

Root position

α−∞ MAX guaranteed at least this
β+∞ MIN allows at most this
v— value so far at this node
Built
0
Skipped
0
MAX node (X to move) MIN node (O to move) caused a cutoff not evaluated ① order examined ≤ bound, not an exact value
Stop and think Some finished nodes read v ≤ 0 rather than v = 0. Why can the search not fill in the exact number?

Because it stopped early, on purpose. A MIN node that cut off has seen some of its children and knows its value is no higher than the best it found. The unseen children could only push it lower. So what comes back is a bound, not a value.

In the first position on this page, one node reports v ≤ 0 while its true minimax value is +1. That is not a bug — it is the algorithm declining to buy information it does not need.

Which gives a sharper description of what alpha–beta is: not a search for values, but a search that propagates bounds on values, and stops as soon as the bounds are tight enough to decide. Only the root, and the nodes along the line actually chosen, come back exact.

Stop and think Run to the end, then switch to plain minimax. Same root value. Coincidence?

A theorem. Alpha–beta always returns the minimax value of the root. The proof is the cutoff rule: a branch is abandoned only after showing that its value cannot reach the root, so abandoning it cannot change the root.

The value is guaranteed identical. The move is not always: when several moves tie, the two searches may report different members of the tie. Equally good, not identical.

07

Same tree, different order

Cutoffs need something to cut against, and α and β only get strong when a good move is examined early. Search the best move first and each sibling is refuted by one child. Search it last and you have paid for the whole tree before learning anything.

The first two positions in the stepper are nearly the same size and prune completely differently. Here is the same effect on the whole game.

Whole game, X to move firstNodes builtvs. minimax
Full minimax — no pruning——
Alpha–beta, cells in order 1…9——
Alpha–beta, centre then corners then edges——
Alpha–beta, moves shuffled——
Takes about a second.

08

Search laboratory

A uniform tree with random leaf values, so you can change one thing at a time. The best ordering is an oracle — it already knows which child is best, which no real program does. It is here to show the ceiling.

Branching factor b3
Depth d4
Move ordering

Nodes in full tree
—
Nodes examined
—
Never examined
—
Work avoided
—
examined — avoided — root value —
ReferenceNodes
Minimax, no pruning — bd leaves—
Alpha–beta, this ordering—
Perfect-ordering ideal — about 2bd/2 leaves—
Stop and think With perfect ordering the count drops to roughly bd/2. Where does the square root come from?

Follow the best line of play down the tree. A node on that line must still examine all its children — it has to prove the best one really is best. But each of those children is a node whose first child is already its best, and that single child immediately produces a bound tight enough to refute all of its siblings.

So the tree branches fully on one level and by one on the next, alternating: b × 1 × b × 1 … across d levels, which is bd/2. Half the levels are free. In a fixed time budget that is roughly twice the depth — which in chess is the difference between a club player and a strong one.

09

Why not solve the whole game once, offline?

The obvious objection

If searching during the game is so expensive, why search at all? Solve every position once, store the best move for each, and at play time just look it up.

This is not a naive idea — it is exactly what we do when we can. Tic-tac-toe has 5,478 reachable positions; you could put the whole solution in a spreadsheet. The question is where that stops working, and the answer arrives faster than most people expect.

GameDistinct positionsPossible gamesSolved?
Tic-tac-toe5,478~105 yes — draw
Connect Four4.5 × 1012~1021 yes, 1988 — first player wins
Checkers5 × 1020~1031 yes, 2007 — draw
Chess~1044~10120 no
Go, 19×192.1 × 10170~10360 no
State-space complexity
How many distinct positions can exist? This is what a lookup table would have to hold, so it bounds the offline approach.
Game-tree complexity
How many distinct games could be played? This is what a search walks, and it is always the larger number — the same position is reached by many move orders.

Read the checkers row again. Five hundred million million million positions. At one byte each that is 500 exabytes, and a byte is not enough to store a move. Checkers was solved — it took eighteen years — but not by tabulating that. Chinook computed perfect endgame databases for every position with ten pieces or fewer, then searched the gap between the opening and those databases. Even the games we have solved were solved by search plus storage, never storage alone.

Chess makes the point sharper. We really do precompute chess endings: the seven-piece tablebases hold about 423 trillion positions and take roughly 18 terabytes compressed. That is a colossal engineering achievement, and it covers about 10−30 of the game. The tail of chess, and not one percent of one percent of anything.

And Go has more legal positions than there are atoms in the observable universe — not a few times more, about 1090 times more. There is no table. There will not be a table.

Which is why we search

Don't solve every position that could ever exist. Solve the tiny region of the tree that the position in front of you can actually reach.
Search narrows what we consider. Alpha–beta narrows how much of that search we have to perform.

Stop and think Connect Four's positions would fit in about 4.5 TB — one large disk. So why was it solved by search in 1988 rather than by building the table?

Because 4.5 TB was not one disk in 1988, and more importantly because you cannot write down the answer without first computing it. Filling the table means evaluating every entry, which is the whole search you were trying to avoid — you have moved the cost, not removed it.

Offline solving pays off only when the answer will be reused enough times to amortise that one-off cost, which is exactly why it is worth doing for endgames: a few hundred distinct piece combinations, reached over and over, in every game ever played afterwards. It is not worth doing for openings, where the tree below each entry is astronomically larger and the position may never recur.

The general lesson is not about board games. Precompute what is small and heavily reused; search what is enormous and specific to the case in front of you.

10

The circularity, and the way out

Alpha–beta works best when you search the best move first. But finding the best move is what you are searching for. That looks like a dead end, and the escape routes are some of the most-used ideas in game programming:

  • Cheap domain knowledge. In chess, try captures, checks and promotions first. They are more often good, and being wrong costs only ordering, never correctness.
  • Killer moves. A move that caused a cutoff in a sibling position will often cause one here too. Keep a couple per depth and try them early.
  • History heuristic. Score every move by how often it has produced a cutoff anywhere in this search, and sort by that score.
  • Transposition tables. The same position arrives by different move orders. Cache what you learned about it — and record whether that entry was an exact value or only a bound, because a cutoff gives you the latter.
  • The previous, shallower search. Which is the trick below.
Stop and think Iterative deepening searches depth 1, then 2, then 3, then 4 — redoing work every time. How can doing extra searches make the whole thing faster?

Two facts collide in a useful way. First, the cost of a tree is dominated by its last level: searching to depth d−1 is a small fraction of searching to d, so the repeated work is cheaper than it sounds.

Second, and this is the real payoff, the depth-d−1 search returns a ranking of the moves. Feed that ranking in as the move order for depth d and you are much closer to the best-first ordering whose ceiling is bd/2. The shallow searches are not overhead; they are how you buy ordering.

So the extra passes pay for themselves, and you get an anytime algorithm for free: interrupt it at any moment and a complete, usable answer from the last finished depth is already in hand.

11

Alpha–beta is from the 1950s. Is the problem finished?

The pruning rule is settled. It is provably correct, it has been understood for seventy years, and nobody is going to improve it — there is nothing to improve, because it already skips exactly what cannot matter and nothing that can.

But “search enormous game spaces well” is not settled at all. Alpha–beta turns out to be the small, stable core of a large system, and almost every part of that system is still an open engineering and research problem.

Alpha–beta

Move ordering

killer moves history heuristic iterative deepening decides how much pruning you get

Evaluation

hand-tuned features learned evaluation quiescence search decides what a cut-off leaf is worth

Memory & time

transposition tables selective deepening parallel search decides what you keep and how long you look

Each box is a live question, and most of them have no settled answer:

  • How do you predict which move to search first, cheaply enough to be worth it?
  • Which branches deserve to be searched deeper than their siblings?
  • Can a learned model evaluate positions better than a human-written function?
  • How do you share a transposition table across many threads without lock contention?
  • How much memory should go to cached positions rather than to deeper search?
  • When should the engine stop thinking and just move?
  • If a cached entry came from a cutoff, it is a bound and not a value — when can you reuse it?
  • What should be carried from one search to the next, and from one game to the next?
The distinction worth keeping

The pruning rule is solved.
Efficient game-tree search is not.

Stop and think AlphaZero beat the strongest conventional chess engine without using alpha–beta at all. Does that make it obsolete?

No — and what actually happened is more interesting. AlphaZero replaced two things at once: it swapped alpha–beta for Monte Carlo tree search, and it swapped a hand-written evaluation function for a neural network. It was easy to read that result as “tree search lost”.

Then Stockfish adopted a small neural evaluation of its own, kept its alpha–beta search, and went back to being at least as strong. Which isolates the variable: the bottleneck was the evaluation, not the search discipline. Today's strongest engines include both kinds, and each has borrowed from the other.

The honest summary is that alpha–beta and MCTS make different bets about where to spend effort — alpha–beta proves things about a narrow, deep slice of the tree; MCTS samples widely and averages. Which bet wins depends on the branching factor, the sharpness of the game, and how good your evaluation is. In Go, with a branching factor near 250, the second bet was better. In chess it was not, and that is still true.

12

And the answer to last week's Q3

You were asked why the agent favours some opening cells over others. Now we can just compute it: every first move, solved to the end.

Press solve to fill this in.

Every opening is a draw

With perfect play from both sides, all nine first moves lead to a draw. So the agent is not choosing between winning and losing openings. It is choosing between openings that give a fallible opponent more ways to go wrong — a different question, and not one minimax asks.

13

The only question that matters

Final challenge MAX already has a move worth at least 8. While examining another move, MIN finds a reply worth 5. Below that reply sit 10,000 unexplored positions. Why is it safe to never look at any of them? Answer without using the word “alpha” or “beta”.

Because MIN is the one choosing there. MIN has already found a reply that holds this branch to 5, and MIN will not volunteer anything better. So the branch is worth at most 5, no matter what those 10,000 positions contain — one of them could be a forced win for MAX and it would still be unreachable, because MIN simply plays the reply worth 5 instead.

MAX, meanwhile, can already get 8 somewhere else. A branch capped at 5 cannot beat a guarantee of 8. So MAX's decision is settled, and 10,000 positions become irrelevant — not unimportant, not approximated, irrelevant.

If you can say that, you understand alpha–beta. α ≥ β is just the two-symbol shorthand for the paragraph you have written.

Go deeper

A ladder of questions

Roughly in order of depth. The first two levels are examinable; the rest is where the subject actually lives.

Level 1 Mechanics
  • What does minimax compute, and what does it assume about the opponent?
  • What does α store? What does β store?
  • At which nodes is each of them updated?
  • Exactly when does a cutoff happen?
Level 2 Why it works
  • Why can α never decrease, and β never increase?
  • Why does α ≥ β make the rest of a node irrelevant?
  • Which player's freedom of choice does the pruning argument depend on?
  • Can alpha–beta ever return a different move than minimax?
Level 3 Information
  • What do you actually need to know about a subtree — a value, or a bound?
  • When is a lower bound enough? When is an upper bound enough?
  • After a cutoff, what exactly has been proved, and what has not?
  • Which nodes in a finished search hold exact values?
Level 4 Search behaviour
  • Does traversal order affect correctness? Does it affect cost?
  • What ordering gives the most pruning? What gives the least?
  • How much of a tree can disappear in the best case?
  • Why is the worst case no better than plain minimax?
Level 5 Practical search
  • If good ordering matters so much, where does the ordering come from?
  • Why does iterative deepening make a search faster rather than slower?
  • What can be reused between one search and the next?
  • What happens when two different move orders reach the same position?
Level 6 When you cannot reach the leaves
  • How do you evaluate a position that is not the end of the game?
  • Does searching one level deeper always give a better decision?
  • What is the horizon effect, and why does quiescence search exist?
  • What does a cutoff prove when the leaf values are themselves estimates?
Level 7 Beyond trees
  • Is a game really a tree, or a graph?
  • What is a transposition, and why are repeated positions expensive?
  • If a cached value came from a cutoff, is it exact or only a bound — and does it matter?
  • What breaks when the game is not zero-sum, or has more than two players?

Use as few words as possible.

Questions to hand in

  1. Play the agent as often as you like. It never loses. Why?

  2. Can we call this agent intelligent? Recall the first lecture on definitions of intelligence.

  3. State the pruning argument without using α or β, and say explicitly where the opponent's freedom to choose enters it.

  4. A finished node reports v ≤ 3. What is known about its true minimax value, what is not, and why was it not worth finding out?

  5. Describe the property a move ordering needs for cutoffs to fire — without using the word “best”.

  6. Two orderings, same position, two different moves returned. Has something gone wrong? Justify either answer.

  7. Iterative deepening does strictly more searching and finishes sooner. Explain the apparent contradiction.