WEEK 4
CHAPTER 4

Adversarial Search

The environment now contains someone who wants you to lose.

Manga page: Balkhash town square. / I'm Max. Nobody beats me. I always plan for YOUR best move. / GULP / But A* only plans for ME!

From search to adversarial search

Ordinary search asks: "Which sequence of my actions reaches the goal?" Adversarial search asks: "Which action is best after accounting for the opponent's best response?" The opponent is part of the model, not noise added later.

Games are classified as deterministic vs stochastic (dice), two-player vs multi-player, zero-sum (one's gain is the other's loss) vs general-sum, and perfect vs imperfect information (poker hides cards). We start with deterministic, two-player, zero-sum, perfect-information games such as tic-tac-toe, chess and Go.

A game as a formal problem

  • S₀: initial state. PLAYER(s): whose turn it is (MAX or MIN).
  • ACTIONS(s): legal moves. RESULT(s, a): transition model.
  • TERMINAL-TEST(s): is the game over? UTILITY(s): final score for MAX (+1 win / 0 draw / −1 loss).

MAX wants a high utility and MIN wants a low one, on the same scale. Tic-tac-toe already has 9 first moves, 8 replies, 7 answers… The full tree is finite but has 255,168 possible games.

The minimax principle

Assume both players are rational. MAX picks the move with the highest guaranteed value, and MIN picks what is worst for MAX. Values are backed up from the leaves to the root:

V(s) = UTILITY(s) if s is terminal V(s) = max over children V(s') if it is MAX's turn V(s) = min over children V(s') if it is MIN's turn

Worked example (lecture tree)

3 MAX = max(3, 2, 2) = 3 322 MINmin(2, …) ≤ 2 < α = 3 → prune! 3128 246 1452
  1. Left MIN node: min(3, 12, 8) = 3.
  2. Middle MIN node: min(2, 4, 6) = 2.
  3. Right MIN node: min(14, 5, 2) = 2.
  4. Root MAX: max(3, 2, 2) = 3, so MAX plays the left move.
WHY NOT GO FOR 14?

The 14 sits in the right subtree, but MIN moves there next and would choose 2. Minimax evaluates what MAX can guarantee, not the biggest leaf in sight.

Minimax is optimal against an optimal opponent, but it is expensive: with branching factor b and depth m it explores O(bm) states. Chess has b ≈ 35 and games of ~80 plies (half-moves), far too many.

Alpha–beta pruning

Many branches can't change the decision. Alpha–beta pruning skips them and returns exactly the same root value as minimax.

  • α = the best value MAX can guarantee so far on the current path (starts at −∞).
  • β = the best value MIN can guarantee so far on the current path (starts at +∞).
  • At a MAX node: α ← max(α, v); stop if v ≥ β. At a MIN node: β ← min(β, v); stop if v ≤ α.
  • Prune when α ≥ β: the remaining siblings can't affect the decision.

On our tree: after the left subtree, α = 3. In the middle subtree the first leaf is 2, so that MIN node is worth at most 2. MAX already has 3, so the leaves 4 and 6 don't matter: pruned. In the right subtree MIN sees 14 (β=14), 5 (β=5), then 2 (β=2 ≤ α). That was the last leaf anyway. Visited leaves: 3, 12, 8, 2, 14, 5, 2, which is 7 of 9.

def alphabeta(state, alpha, beta, maximizing):
    if terminal(state): return utility(state)
    if maximizing:
        v = float("-inf")
        for child in successors(state):
            v = max(v, alphabeta(child, alpha, beta, False))
            alpha = max(alpha, v)
            if alpha >= beta: break        # β-cutoff
        return v
    else:
        v = float("inf")
        for child in successors(state):
            v = min(v, alphabeta(child, alpha, beta, True))
            beta = min(beta, v)
            if alpha >= beta: break        # α-cutoff
        return v

Move ordering matters. If the best moves are tried first, bounds tighten early and pruning is strongest. With perfect ordering alpha–beta examines about O(bm/2) nodes, so it can search twice as deep in the same time.

TRY IT! Beat Max at tic-tac-toe (he uses minimax + alpha–beta)

You are X. Click a square.

Nodes searched for Max's last move: minimax: – alpha–beta: –

Spoiler: with perfect play, tic-tac-toe is a draw. You can't beat Max, only tie. Watch how many fewer nodes alpha–beta needs for the same move.

Real games: depth limits & evaluation functions

Real games can't be searched to the end. We stop at a depth limit d and replace the true utility with an evaluation function that estimates how good a position is, usually a weighted sum of features:

Eval(s) = w₁·f₁(s) + w₂·f₂(s) + … + wₙ·fₙ(s) chess features: material, mobility, king safety, centre control

Compare: an A* heuristic estimates remaining path cost; a game evaluation estimates the strategic quality of a state. Both inject domain knowledge into search.

Horizon effect: a disaster just beyond the depth limit stays invisible, so a position may look great while a loss is one move away. Deeper search and quiescence search (extending tactically unstable positions until quiet positions are reached) help but don't fully remove it.

Practical 4 warm-up: a delivery price war (MAX = our company)

Our strategy ↓ / competitor →Price cutNo changeFaster deliveryMIN picks
A: Low price8644
B: Standard3753
C: Express2911

Payoffs are invented profit (million KZT) in a simplified zero-sum model. Minimax: MIN answers each strategy with its smallest payoff (4, 3, 1), and MAX takes the largest of those, so it plays A with a guaranteed value of 4. C has the tempting 9, but a rational competitor would never allow it.

When the opponent is chance: expectimax

Minimax assumes the uncontrolled choice is adversarial. Dice, slipping wheels or a random ghost aren't trying to beat you, so worst-case thinking is too pessimistic. Expectimax replaces MIN nodes with chance nodes that compute an expected value:

V(chance) = Σ P(s') · V(s') example: ½·8 + ⅓·24 + ⅙·(−12) = 4 + 8 − 2 = 10

The rule of thumb: use minimax against strategic opponents and expectimax when a probability model describes the uncertainty better. Treating an adversary as random is dangerously optimistic. Treating randomness as an adversary is needlessly pessimistic.

MILESTONES

Checkers was solved in 2007: perfect play is a draw. Chess: IBM's Deep Blue beat Garry Kasparov in 1997 using alpha–beta search on special hardware. Go (b ≈ 250) resisted until AlphaGo (2016) combined tree search with neural-network evaluation learned by self-play.

AI vs HUMAN

A human grandmaster considers only a handful of candidate moves but evaluates them with deep intuition. Deep Blue searched about 200 million positions per second. Modern engines combine both: strong learned intuition plus fast search.

MINI-QUIZ

1. Does alpha–beta pruning change the minimax value at the root?

It only skips branches that cannot affect the decision. Alpha–beta is an optimisation of minimax, not a different objective.

2. A MIN node has α = 5 and finds a child worth 3. What happens?

MIN will get ≤ 3 here, and MAX already has 5 elsewhere. 3 ≤ α means this branch can't beat MAX's alternative, so the remaining children are skipped.

3. A dice game: which algorithm models the dice best?

Dice outcomes have probabilities, so chance nodes average them.
Manga page: A draw against me? Not bad, little robot. / But real life has DICE, not just opponents. / Then I'll learn to decide under uncertainty!
4