Home Module 1 - Introduction to AI Module 2 - Problem-Solving & Search Module 3 - Uncertainty in AI Module 4 - Games & CSP Module 5 - AI in Practice & Ethics Important Questions
Module 4 of 5

Game Playing and Constraint Satisfaction Problems

Module 4 covers two structurally different but related problem classes. Game playing introduces adversarial search - an opponent is actively trying to defeat the agent, requiring algorithms (Minimax, Alpha-Beta, MCTS) fundamentally different from Module 1–2's single-agent search. Constraint Satisfaction Problems (CSPs) reframe search as finding variable assignments that satisfy a set of constraints - a structure underlying scheduling, planning, and resource-allocation problems across AI.

12 Hours
8 Core Topics
CO4 - Create solutions to constrained problems (L5)
4.1

Introduction to Game Theory in AI & Nash Equilibrium

Game theory is the mathematical study of strategic interaction between multiple rational decision-makers, where each agent's outcome depends not just on its own action but on the actions of others. This is fundamentally different from single-agent search - there is no single "optimal path," only optimal strategies in light of an opponent's strategy.

📘 Definition - Game

An AI game is formally defined by: a set of players, an initial state, an ACTIONS(s) function listing legal moves, a RESULT(s,a) transition model, a TERMINAL-TEST(s), and a UTILITY(s,p) function giving the numeric outcome for player p at terminal state s.

Classifying Games

DimensionCategoriesExample
Number of playersTwo-player vs. multi-playerChess (2) vs. Poker (multi)
Sum typeZero-sum (one's gain is exactly the other's loss) vs. General-sumChess (zero-sum) vs. economic negotiation (general-sum)
InformationPerfect information (fully observable) vs. imperfect informationChess (perfect) vs. Poker (imperfect)
DeterminismDeterministic vs. stochastic (chance elements)Chess (deterministic) vs. Backgammon (dice, stochastic)

Nash Equilibrium

📘 Definition - Nash Equilibrium

A Nash Equilibrium is a set of strategies (one per player) such that no player can improve their own outcome by unilaterally changing only their own strategy, assuming all other players keep their strategies fixed. Every finite game has at least one Nash equilibrium (possibly in mixed/randomized strategies) - proven by John Nash (1950).

Worked Example - Prisoner's Dilemma

B: CooperateB: Defect
A: CooperateA: −1, B: −1A: −3, B: 0
A: DefectA: 0, B: −3A: −2, B: −2 (Nash Equilibrium)

(Defect, Defect) is the unique Nash equilibrium: given that B defects, A's best response is to also defect (−2 beats −3); symmetric for B. Notably, (Cooperate, Cooperate) would give both players a better outcome (−1,−1) - but it isn't stable, since either player could unilaterally improve by switching to Defect. This famous tension (individually rational ≠ collectively optimal) is a cornerstone result of game theory.

Pure vs. Mixed Strategy Equilibria

TypeDescription
Pure StrategyEach player deterministically commits to one specific action
Mixed StrategyA player randomizes over actions according to a probability distribution - necessary in games (like Rock-Paper-Scissors) with no pure-strategy equilibrium
💡 Real-world example

Two competing companies deciding whether to cut prices mirrors the Prisoner's Dilemma: both cutting prices (a "price war") is often the Nash equilibrium even though both companies would profit more if both held prices steady - neither can unilaterally hold prices without losing market share to the other.

Game Theory vs. Classical Adversarial Search

This course's later topics (Minimax, Alpha-Beta) focus specifically on zero-sum, two-player, perfect-information, deterministic games - the simplest, most tractable game-theoretic setting, where Nash equilibrium for one player reduces exactly to the Minimax strategy.

🔑 Key Points
  • Games are classified by player count, sum type, information, and determinism.
  • Nash Equilibrium: no player benefits from unilaterally deviating.
  • In two-player zero-sum games with perfect information, Nash equilibrium ≡ the Minimax solution.

Interview Questions

Q. Why is mutual cooperation not a Nash Equilibrium in the Prisoner's Dilemma, even though it gives both players a better outcome than mutual defection?

Nash Equilibrium only requires stability against unilateral deviation, not collective optimality. At (Cooperate, Cooperate), either player can improve their own payoff by unilaterally switching to Defect (going from −1 to 0), so it fails the no-incentive-to-deviate test, despite being Pareto-superior to (Defect, Defect) for both players jointly.

4.2

Optimal Decisions in Games: The Minimax Algorithm

Minimax is the foundational algorithm for two-player, zero-sum, deterministic, perfect-information games (e.g., Tic-Tac-Toe, Chess, Checkers). It's also implemented in this course's Lab Experiment 7.

📘 Definition

Minimax assumes both players play optimally: the MAX player chooses the move maximizing the eventual outcome (utility), while the MIN player (the opponent) chooses the move minimizing it. The algorithm recursively computes the minimax value of every node by propagating terminal utilities back up the game tree.

MINIMAX(s) =
  UTILITY(s)    if TERMINAL-TEST(s)
  maxa MINIMAX(RESULT(s,a))    if PLAYER(s) = MAX
  mina MINIMAX(RESULT(s,a))    if PLAYER(s) = MIN

Worked Example - Small Game Tree

MAX: 3
MIN: 3
MIN: 2
3
12
2
8

Fig 4.1 - Leaves are terminal utilities. MIN node picks min(3,12)=3; MIN node picks min(2,8)=2; MAX node picks max(3,2)=3. The root's minimax value is 3.

Python
def minimax(state, depth, maximizing_player):
    if depth == 0 or is_terminal(state):
        return utility(state)

    if maximizing_player:
        best = float('-inf')
        for action in actions(state):
            value = minimax(result(state, action), depth - 1, False)
            best = max(best, value)
        return best
    else:
        best = float('inf')
        for action in actions(state):
            value = minimax(result(state, action), depth - 1, True)
            best = min(best, value)
        return best

def best_move(state):
    return max(actions(state),
               key=lambda a: minimax(result(state, a), depth - 1, False))

Properties

PropertyResultExplanation
CompletenessYes, if the game tree is finiteWill always find a value if the tree terminates
OptimalityYes, against an optimal opponentGuarantees the best achievable outcome assuming perfect adversarial play
Time ComplexityO(bm)b = branching factor (legal moves), m = maximum game depth
Space ComplexityO(bm)Like DFS - only needs to store one path at a time
⚠ Practical Limitation

For real games like chess (b≈35, m≈80+ for a full game), exploring the entire tree is computationally impossible. In practice, Minimax is combined with a depth-limited cutoff and an evaluation function Eval(s) that estimates the value of non-terminal states - turning the algorithm into "Minimax with a heuristic evaluation," used in real engines like the early Deep Blue.

Applications

  • Tic-Tac-Toe, Checkers, Chess engines (Lab Experiment 7)
  • Any two-player, zero-sum, perfect-information game AI
  • Adversarial decision-making in security/game-theoretic simulations
✓ Advantages
  • Guarantees the optimal move against a perfectly rational opponent
  • Conceptually simple recursive structure
✗ Disadvantages
  • Exponential time complexity - infeasible for deep/complex games without pruning
  • Assumes the opponent is perfectly rational - performs sub-optimally against weak/random opponents (though never worse than guaranteed)
  • Requires a depth cutoff + evaluation function for large games, introducing approximation
🔑 Key Points
  • MAX maximizes, MIN minimizes - recursion propagates terminal utilities up the tree.
  • Optimal but exponential: O(bm) time - Alpha-Beta pruning (next topic) is essential in practice.
  • Real engines use depth-limited Minimax + heuristic evaluation function.

Interview & Exam Questions

Q. What assumption does Minimax make about the opponent, and what happens if that assumption is wrong?

Minimax assumes the opponent always plays optimally (minimizing the MAX player's utility). If the actual opponent plays sub-optimally or randomly, Minimax's chosen move is still safe (guarantees at least the minimax value) but may not be the move that maximizes exploitation of the weaker opponent - a different algorithm (like expectimax) would better exploit a known-suboptimal opponent.

Q. Trace Minimax on a game tree and explain why the root's value represents the "guaranteed" outcome.

Each MIN node returns the minimum of its children (the opponent's best response), and each MAX node returns the maximum of its children (the agent's best choice) - by induction from the leaves upward, the value at any node represents the outcome both players would achieve from that point onward under optimal play by both sides, so the root's value is the best score the MAX player can guarantee regardless of how well the opponent plays.

4.3

Optimal Decisions in Games: Alpha-Beta Pruning

Alpha-Beta Pruning computes the exact same result as Minimax, but prunes away branches that provably cannot affect the final decision - dramatically reducing the number of nodes explored without sacrificing optimality.

📘 Definition

Alpha-Beta Pruning maintains two bounds during the Minimax recursion: α (alpha) = the best value MAX is guaranteed so far along the current path, and β (beta) = the best value MIN is guaranteed so far. Whenever α ≥ β at any node, the remaining branches at that node are pruned (skipped entirely), since they cannot influence the final decision.

Step-by-Step Working

  1. Initialize α = −∞, β = +∞ at the root.
  2. At a MAX node: update α = max(α, child's value) after evaluating each child. If α ≥ β, prune remaining children (β-cutoff).
  3. At a MIN node: update β = min(β, child's value) after evaluating each child. If β ≤ α, prune remaining children (α-cutoff).
  4. Pass the current (α, β) values down to recursive calls - pruning information flows from ancestors to descendants.
  5. Return the same minimax value Minimax would have computed, having explored fewer nodes.
Python
def alphabeta(state, depth, alpha, beta, maximizing_player):
    if depth == 0 or is_terminal(state):
        return utility(state)

    if maximizing_player:
        value = float('-inf')
        for action in actions(state):
            value = max(value, alphabeta(result(state, action), depth-1, alpha, beta, False))
            alpha = max(alpha, value)
            if alpha >= beta:
                break          # β cutoff - prune remaining siblings
        return value
    else:
        value = float('inf')
        for action in actions(state):
            value = min(value, alphabeta(result(state, action), depth-1, alpha, beta, True))
            beta = min(beta, value)
            if beta <= alpha:
                break          # α cutoff - prune remaining siblings
        return value

# initial call: alphabeta(root, max_depth, float('-inf'), float('inf'), True)

Worked Example with Pruning Shown

MAX
MIN: 3
MIN: pruned
3
5
2
✂ skip

Fig 4.2 - After exploring leaf "3" then "5" under the first MIN node (value settles at min=3), MAX has α=3. The second MIN branch finds a leaf "2" first; since β=2≤α=3, the rest of that branch is pruned - it can't beat 3, so MAX would never choose it anyway

Move Ordering - Critical for Pruning Efficiency

⚠ Why Move Ordering Matters

Alpha-Beta's pruning efficiency depends heavily on the order moves are explored. With a perfect move ordering (best moves examined first), Alpha-Beta reduces the effective branching factor from b to √b, allowing search to twice the depth in the same time. With poor (worst-case) ordering, Alpha-Beta degenerates to exploring exactly as many nodes as plain Minimax - no benefit at all.

Best-Case vs Worst-Case Complexity

OrderingTime ComplexityPractical Effect
Worst-case (poor ordering)O(bm)Same as plain Minimax - no pruning benefit
Best-case (optimal ordering)O(bm/2)Effectively doubles the depth searchable in the same time budget
Random ordering (typical)Between the two extremesStill a substantial practical speedup over plain Minimax

Properties

PropertyResult
CompletenessYes (same as Minimax - finite tree)
OptimalityYes - produces the exact same result as Minimax, just faster
Space ComplexityO(bm), same as Minimax
✓ Advantages
  • Identical correctness to Minimax - no loss of optimality
  • Dramatic practical speedup, especially with good move ordering
  • Enables searching significantly deeper game trees within the same time budget
✗ Disadvantages
  • Pruning benefit highly dependent on move ordering quality
  • Still exponential in the worst case
  • More complex to implement correctly than plain Minimax (tracking α, β through recursion)

Applications

  • Chess engines (historically including early IBM Deep Blue) - Lab Experiment 7 of this course
  • Any deep adversarial game-tree search where plain Minimax is too slow
  • General two-player game AI in commercial games
🔑 Key Points
  • α = best value MAX can guarantee so far; β = best value MIN can guarantee so far.
  • Prune when α ≥ β - that branch cannot affect the final decision.
  • Same result as Minimax, but O(bm/2) best case vs O(bm) - move ordering is critical.

Interview & Exam Questions

Q. Explain why Alpha-Beta Pruning never changes the final Minimax decision, only the number of nodes explored.

Pruning only discards branches that are provably irrelevant: if at a MIN node β ≤ α, it means this node's value can be at most β, which is no better for MIN's opponent (MAX) than a value MAX has already secured elsewhere (α). Since MAX would never choose this branch over the already-better alternative, fully evaluating it cannot change the parent's decision - so it's safe to skip, preserving the exact same root value Minimax would compute.

Q. Why does move ordering dramatically affect Alpha-Beta's efficiency?

Pruning only occurs once α and β bounds have been tightened enough that a later sibling can be proven irrelevant. If the best move is explored first, the bounds tighten quickly, enabling more pruning of subsequent (worse) branches. If the worst moves are explored first, bounds tighten slowly or not at all before all children must be examined, eliminating most or all of the pruning benefit - in the absolute worst case, no nodes get pruned at all.

4.4

Monte-Carlo Tree Search: Basics and Application in Game Playing

Minimax and Alpha-Beta need a hand-crafted evaluation function and struggle with enormous branching factors (e.g., Go's b≈250). Monte Carlo Tree Search (MCTS) instead estimates the value of moves via repeated random simulation (playouts), requiring no domain-specific evaluation function - this is the technique behind AlphaGo's historic 2016 victory.

📘 Definition

MCTS builds a search tree incrementally and asymmetrically, guided by the outcomes of randomized simulations ("rollouts") played out to the end of the game, using statistics gathered to focus search effort on the most promising moves.

The Four Phases of MCTS (repeated every iteration)

  1. Selection - starting at the root, recursively select child nodes using a selection policy (typically UCB1/UCT) until a node with unexplored children (or a terminal state) is reached.
  2. Expansion - if the selected node is non-terminal and has unexplored actions, add one (or more) new child node(s) to the tree.
  3. Simulation (Rollout) - from the newly expanded node, play out the rest of the game using a fast, simple policy (often random moves) until reaching a terminal state.
  4. Backpropagation - propagate the simulation's result (win/loss/score) back up through every node visited in this iteration, updating visit counts and win statistics.
1. Selection (UCT)
2. Expansion
3. Simulation (random rollout)
4. Backpropagation
↻ repeat thousands of times

Fig 4.3 - One MCTS iteration. Repeating this loop thousands of times builds increasingly accurate value estimates for the root's candidate moves

UCB1 / UCT - The Selection Formula

📘 Definition - UCT (Upper Confidence bounds applied to Trees)

At each node, MCTS selects the child maximizing the UCB1 score, which balances exploitation (favoring nodes with high win rate) against exploration (favoring under-visited nodes):

UCB1(child) = (wi / ni) + C × √(ln N / ni)

wi/ni = win ratio (exploitation)  |  N = parent visit count, ni = child visit count (exploration bonus)  |  C = exploration constant (commonly √2)

Pseudocode
function MCTS(root_state, iterations):
    root ← Node(root_state)
    for i in range(iterations):
        node ← root
        # 1. Selection
        while node is fully expanded and not terminal:
            node ← SELECT-UCB1-CHILD(node)
        # 2. Expansion
        if node is not terminal:
            node ← EXPAND(node)               # add one new child
        # 3. Simulation
        result ← RANDOM-ROLLOUT(node.state)
        # 4. Backpropagation
        while node is not null:
            node.visits += 1
            node.wins += result
            node ← node.parent
    return BEST-CHILD(root, criterion="most visited")   # robust choice

Why MCTS Beats Minimax in Large/Complex Games

AspectMinimax + Alpha-BetaMCTS
Needs an evaluation function?Yes - must hand-craft Eval(s)No - uses random rollouts instead
Tree growthSymmetric, fixed-depth explorationAsymmetric - focuses effort on promising branches
Anytime algorithm?No - needs to finish a depth level for a usable resultYes - can be stopped at any time and still return the current best estimate
Best suited forGames with low branching factor, easy evaluation (chess)Games with huge branching factor, hard evaluation (Go)
💡 Real-world example - AlphaGo

AlphaGo combined MCTS with deep neural networks: a policy network to guide which moves to expand (replacing pure random rollouts with smarter ones) and a value network to estimate position quality (reducing reliance on full random rollouts) - this hybrid was decisive in defeating world champion Lee Sedol in 2016.

Properties

PropertyResult
CompletenessYes, in the limit of infinite iterations (eventually explores the full tree)
OptimalityConverges to the optimal move as iterations → ∞ (with UCT's exploration guarantee)
Anytime behaviorYes - can return a reasonable answer even if interrupted early
✓ Advantages
  • No hand-crafted evaluation function required - scales to domains where evaluation is hard to define
  • Anytime algorithm - usable result available at any computation budget
  • Naturally handles huge branching factors via asymmetric tree growth
✗ Disadvantages
  • Needs many simulations for accurate estimates - can be slow to converge in tactically sharp positions
  • Pure random rollouts can miss short tactical traps that Minimax would catch directly
  • Performance depends on rollout policy quality and exploration constant tuning

Applications

  • Go-playing AI (AlphaGo, AlphaZero)
  • General game playing competitions
  • Real-time strategy game AI
  • Resource scheduling and planning under uncertainty
🔑 Key Points
  • 4 phases: Selection (UCT) → Expansion → Simulation (rollout) → Backpropagation.
  • UCB1 formula balances exploitation (win rate) and exploration (visit count bonus).
  • No evaluation function needed - ideal for huge branching factors like Go.

Interview Questions

Q. Why is MCTS better suited to Go than Minimax with Alpha-Beta pruning?

Go has an enormous branching factor (~250 per move) and no simple, reliable hand-crafted evaluation function for intermediate positions, unlike chess's material-count heuristics. Minimax with Alpha-Beta needs both a manageable branching factor and a good evaluation function to be effective at depth, while MCTS needs neither - it estimates position value purely through random simulation outcomes, scaling naturally to Go's complexity.

Q. Explain the exploration-exploitation trade-off captured by the UCB1 formula in MCTS.

The win-ratio term (wᵢ/nᵢ) favors exploitation - nodes that have performed well so far. The second term, C·√(ln N / nᵢ), grows larger for nodes visited less often (small nᵢ), favoring exploration of under-tried moves. Balancing these prevents MCTS from prematurely committing to an early lucky-looking move while still focusing most simulations on genuinely promising branches.

4.5

Stochastic Games and Partially Observable Games

Minimax and Alpha-Beta assumed deterministic, perfect-information games. Many real games involve chance elements (dice, card draws) or hidden information (opponent's hand) - this topic extends game-tree search to handle both.

Part A: Stochastic Games - Expectimax

📘 Definition - Expectimax

For games with an element of chance (e.g., Backgammon's dice rolls), the game tree includes CHANCE nodes alongside MAX and MIN nodes. A chance node's value is the expected value (probability-weighted average) over all possible chance outcomes, rather than a strict max or min.

EXPECTIMAX(s) = Σr P(r) × MINIMAX/EXPECTIMAX(RESULT(s,r))   at a CHANCE node, summing over all chance outcomes r
MAX
CHANCE p=0.5
CHANCE p=0.5
2
8
4
6

Fig 4.4 - Expectimax: each CHANCE node = 0.5×(left child) + 0.5×(right child), giving expected values of 5 and 5; MAX then chooses max(5,5)=5

⚠ Why Alpha-Beta Pruning Doesn't Directly Apply to CHANCE Nodes

Standard Alpha-Beta pruning relies on the fact that a single very good or very bad child can determine a MAX/MIN node's entire value. A CHANCE node's value is an average, so no single child outcome alone can guarantee a cutoff - pruning at chance nodes requires bounded utility values and more specialized techniques (e.g., "star1"/"star2" pruning).

Part B: Partially Observable Games

📘 Definition

In a partially observable game (e.g., Poker, Stratego), players cannot see the complete game state - each player maintains a belief state over possible true states (analogous to Module 2's belief-state search), and optimal play often requires randomized (mixed) strategies to avoid being predictable.

Key Concepts in Imperfect-Information Games

  • Information sets - the set of game states a player cannot distinguish between, given what they've observed so far.
  • Bluffing - a rational strategy in games like Poker precisely because of hidden information: deliberately misrepresenting one's true state (hand strength) to manipulate the opponent's beliefs.
  • Mixed strategies are essential - a deterministic (pure) strategy in an imperfect-information game can often be exploited once the opponent learns the pattern, whereas a well-calibrated randomized strategy cannot.
💡 Real-world example

In Texas Hold'em Poker, a player with a weak hand may "bluff" by betting aggressively. Game-theoretically optimal play requires bluffing with some calibrated, non-zero frequency - bluffing 0% of the time makes a player's bets perfectly informative (and exploitable), while bluffing too often is equally exploitable in the other direction.

Comparison Summary

Game TypeAlgorithmKey Addition
Deterministic, perfect infoMinimax / Alpha-Beta-
Stochastic, perfect infoExpectimaxCHANCE nodes - expected value averaging
Deterministic, imperfect infoSearch over belief states / information setsReasoning over what the opponent could know
Stochastic, imperfect infoCombination (e.g., counterfactual regret minimization in modern Poker AI)Mixed strategies + belief updates + chance nodes
🔑 Key Points
  • Stochastic games add CHANCE nodes, evaluated via Expectimax (expected value, not max/min).
  • Standard Alpha-Beta pruning doesn't directly apply to chance nodes.
  • Imperfect-information games require reasoning over belief/information sets and often mixed strategies to avoid predictability.

Interview Questions

Q. Why must a chance node in Expectimax compute an expected value rather than a max or min?

A chance node represents an event the players don't control (e.g., a dice roll) - neither player chooses the outcome, so neither maximizing nor minimizing logic applies. Since each possible outcome occurs with some known probability, the rational way to summarize the node's value is the probability-weighted average (expectation) over all outcomes.

Q. Why is bluffing a rational, not merely deceptive, strategy in game-theoretic terms?

In an imperfect-information game, always playing predictably (e.g., betting only with strong hands) lets the opponent infer hidden information from observed actions, making the player exploitable. Game-theoretically optimal play requires randomizing actions - including occasionally bluffing - at calibrated frequencies so opponents cannot reliably distinguish strong from weak true states, which is a property of Nash equilibrium mixed strategies, not simply "tricking" the opponent.

4.6

Constraint Satisfaction Problems: Overview and Structure

CSPs are a different - and very powerful - way to frame a search problem: instead of finding a path through a state space, the goal is to find an assignment of values to variables that satisfies all problem-specific constraints.

📘 Definition - CSP

A Constraint Satisfaction Problem is defined by a triple (X, D, C): a set of variables X = {X₁,…,Xₙ}, a set of domains D = {D₁,…,Dₙ} (the possible values each variable can take), and a set of constraints C specifying allowable combinations of values for subsets of variables.

Classic Example - Map Coloring

Color a map's regions so that no two adjacent regions share a color, using the fewest possible colors. Variables = regions; Domain = {Red, Green, Blue}; Constraints = "adjacent regions must differ."

WA NT Q SA

Fig 4.5 - Map-coloring CSP: WA and SA both colored Pine (green) since they aren't adjacent; NT and SA must differ since they are - a valid 3-coloring satisfying all constraints

Types of Constraints

TypeDescriptionExample
UnaryRestricts a single variable's domainSA ≠ Green (a specific region cannot be a specific color)
BinaryRelates exactly two variablesWA ≠ NT (adjacency constraint)
Higher-order (n-ary)Relates three or more variables simultaneouslyCryptarithmetic column-sum constraints
GlobalA higher-order constraint with a specific, efficiently-handled structureALL-DIFFERENT(X₁,…,Xₙ) - common in Sudoku/scheduling

Constraint Graph & Structure

📘 Definition - Constraint Graph

For binary CSPs, the constraint graph has one node per variable and one edge per binary constraint. The graph's structure has a major impact on solving difficulty: tree-structured CSPs (no cycles) can be solved in time linear in the number of variables, while general (densely cyclic) CSPs are NP-hard in the worst case.

Real-World CSP Examples

  • Sudoku - 81 variables (cells), domain {1..9}, ALL-DIFFERENT constraints per row/column/box.
  • N-Queens - n variables (one per column, value = row), constraints: no two queens share a row, column, or diagonal.
  • Class/Exam Scheduling - variables = courses, domains = time slots, constraints = no professor/room double-booked.
  • Cryptarithmetic (e.g., SEND+MORE=MONEY) - variables = letters, domain = digits 0-9, constraints = all-different + arithmetic column sums.

Why CSP Formulation Helps

Unlike general state-space search, CSPs expose problem structure explicitly (which variables interact, and how), enabling powerful domain-independent techniques: constraint propagation (inferring additional restrictions before search even begins), heuristics like Most-Constrained-Variable and Least-Constraining-Value, and graph-structure exploitation (e.g., tree decomposition).

🔑 Key Points
  • CSP = (Variables, Domains, Constraints); goal is a consistent, complete assignment.
  • Constraints classified as unary, binary, n-ary/higher-order, or global.
  • Constraint graph structure (tree vs. general) heavily impacts solvability/efficiency.
Q. Why are tree-structured CSPs much easier to solve than general CSPs?

In a tree-structured constraint graph, there are no cycles, so once the tree is processed (e.g., via directional arc-consistency from leaves to root, then assignment from root to leaves), no variable's choice can create a downstream conflict that wasn't already resolved - this allows solving in time linear in the number of variables, versus exponential worst-case time for general (cyclic) graphs.

4.7

Backtracking Search for CSP

📘 Definition

Backtracking Search is a depth-first search over partial assignments: it assigns a value to one variable at a time, checking constraints as it goes, and backtracks (undoes the most recent assignment and tries a different value) whenever a constraint is violated or no legal value remains for a variable.

Step-by-Step Working

  1. If all variables are assigned consistently, return the assignment as a solution.
  2. Select an unassigned variable (using a selection heuristic - see below).
  3. For each value in that variable's domain (ordered by a value heuristic):
  4. Check if assigning this value is consistent with all constraints involving already-assigned variables.
  5. If consistent, assign it and recursively continue to the next variable.
  6. If the recursive call fails, undo this assignment ("backtrack") and try the next value.
  7. If no value works for this variable, return failure (forcing the parent call to backtrack further).
Pseudocode
function BACKTRACKING-SEARCH(csp):
    return BACKTRACK({}, csp)

function BACKTRACK(assignment, csp):
    if assignment is complete: return assignment
    var ← SELECT-UNASSIGNED-VARIABLE(csp, assignment)
    for each value in ORDER-DOMAIN-VALUES(var, assignment, csp):
        if value is consistent with assignment (per csp.CONSTRAINTS):
            add {var = value} to assignment
            inferences ← INFERENCE(csp, var, value)        # e.g., forward checking
            if inferences ≠ failure:
                add inferences to assignment
                result ← BACKTRACK(assignment, csp)
                if result ≠ failure: return result
            remove {var = value} and inferences from assignment   # undo / backtrack
    return failure

Variable & Value Ordering Heuristics

HeuristicStrategyWhy it helps
Minimum Remaining Values (MRV)Choose the variable with the fewest legal values remaining"Fail-fast" - quickly detects dead-ends, pruning the search tree early
Degree HeuristicChoose the variable involved in the most constraints with other unassigned variablesTie-breaker for MRV; reduces future branching the most
Least Constraining Value (LCV)For value ordering: choose the value that rules out the fewest choices for neighboring variablesKeeps the most options open for future assignments, reducing backtracking

Constraint Propagation: Forward Checking & Arc Consistency

Plain backtracking only checks constraints involving already-assigned variables - it can waste time exploring branches doomed to fail much later. Constraint propagation proactively detects such failures earlier:

  • Forward Checking - whenever a variable is assigned, immediately remove inconsistent values from the domains of its unassigned neighbors; if any neighbor's domain becomes empty, backtrack immediately rather than waiting to reach that variable.
  • Arc Consistency (AC-3) - a stronger form of propagation: an arc X→Y is consistent if, for every value in X's domain, there exists some compatible value in Y's domain; AC-3 repeatedly enforces this across all arcs until no further domain values can be removed, often dramatically shrinking the search space before any guessing occurs.
💡 Worked example - N-Queens with MRV

Placing the first queen in column 1 immediately restricts which rows are legal for column 2 (same row/diagonal forbidden). MRV picks whichever remaining column has the fewest legal row options next, rather than naively going left-to-right - this can detect an unsolvable partial placement far sooner than naive ordering.

Properties

PropertyResult
CompletenessYes - explores the full (finite) assignment space if needed, will find a solution if one exists
Time ComplexityO(dn) worst case (d = domain size, n = number of variables); drastically reduced in practice with good heuristics + propagation
Space ComplexityO(n) - only the current partial assignment path needs storing (DFS-like)
✓ Advantages
  • Complete and correct - guaranteed to find a solution if one exists
  • Combines naturally with powerful heuristics (MRV, degree, LCV) and propagation (forward checking, AC-3) for large speedups
  • Memory-efficient - linear space, like DFS
✗ Disadvantages
  • Worst-case exponential time without good heuristics/propagation
  • Performance highly sensitive to variable/value ordering choices
  • Naive backtracking (without propagation) can "thrash" - repeatedly rediscovering the same failure pattern

Applications

  • Sudoku solvers, N-Queens - common CSP teaching examples
  • Class/exam timetabling and resource scheduling
  • Compiler register allocation
  • Configuration problems (e.g., product/component compatibility)
🔑 Key Points
  • Backtracking = DFS over partial assignments + constraint checking + undo on failure.
  • MRV and Degree heuristics order variables; LCV orders values.
  • Forward checking and AC-3 propagate constraints early, pruning the search tree before failures are reached.

Interview & Exam Questions

Q. Why is the Minimum Remaining Values heuristic called a "fail-fast" strategy?

By always assigning the most constrained variable (fewest remaining legal values) next, the algorithm is more likely to discover - early in the search - that a variable has zero legal values left, signaling an unsolvable partial assignment. Detecting this failure as early as possible avoids wasting time exploring deep, doomed branches that less-constrained variable orderings would only discover much later.

Q. What is the difference between Forward Checking and full Arc Consistency (AC-3)?

Forward Checking only checks constraints directly between the just-assigned variable and its unassigned neighbors, removing inconsistent values from their domains. AC-3 is more thorough: it enforces consistency across all arcs in the constraint graph repeatedly, propagating the effect of domain reductions transitively through the whole graph, catching some failures that Forward Checking alone would miss - at a higher computational cost per propagation step.

4.8

Local Search for CSP: Min-Conflicts Algorithm

Backtracking builds a solution incrementally, variable by variable. Min-Conflicts takes a completely different approach inspired by Module 2's local search: start with a complete (but possibly invalid) assignment of all variables, then iteratively repair conflicts.

📘 Definition

The Min-Conflicts algorithm begins with a random complete assignment to all variables. At each step, it randomly selects a conflicted variable (one violating at least one constraint) and reassigns it to the value that minimizes the number of constraint violations with its neighbors, ties broken randomly. This repeats until no conflicts remain (a solution) or a maximum iteration count is reached.

Step-by-Step Working

  1. Generate an initial complete assignment (often randomly, or using a greedy heuristic).
  2. If the assignment satisfies all constraints, return it as the solution.
  3. Otherwise, randomly select any variable involved in a constraint violation.
  4. Reassign that variable to the value minimizing the total number of conflicts (ties broken randomly).
  5. Repeat from step 2, up to a maximum number of steps.
Python
import random

def min_conflicts(csp, max_steps=10000):
    assignment = {var: random.choice(csp.domains[var]) for var in csp.variables}
    for step in range(max_steps):
        conflicted = [v for v in csp.variables if csp.conflicts(v, assignment) > 0]
        if not conflicted:
            return assignment                       # solution found
        var = random.choice(conflicted)
        # choose value minimizing conflicts for this variable
        best_value = min(csp.domains[var],
                          key=lambda val: csp.conflicts_if(var, val, assignment))
        assignment[var] = best_value
    return None    # failure within step budget

Worked Example - N-Queens with Min-Conflicts

Min-Conflicts is famously effective on N-Queens: starting from a random placement of N queens (one per column), it repeatedly picks a queen under attack and moves it to the row minimizing the number of attacking queens. Remarkably, this solves even the million-queens problem in roughly constant time per queen - a striking contrast to backtracking, which scales poorly for very large N.

·
Q
·
·
·
·
·
Q
Q
·
·
·
·
·
Q
·

Fig 4.6 - A conflict-free 4-Queens solution that Min-Conflicts can reach by repeatedly moving the most-attacked queen to its least-conflicting row

Min-Conflicts vs. Backtracking - Comparison

AspectBacktracking SearchMin-Conflicts
Starting pointEmpty/partial assignment, built up incrementallyComplete (possibly invalid) random assignment, repaired iteratively
Search styleSystematic depth-first constructionLocal search / iterative repair (like Hill Climbing over CSPs)
CompletenessComplete (will find a solution if one exists)Incomplete - may get stuck or exceed step budget without finding a solution
Performance on large, easy CSPsCan be slow for very large N (e.g., N-Queens)Extremely fast in practice for many large, loosely-constrained CSPs
Performance on tightly-constrained CSPsStill complete, can use propagation to stay efficientCan struggle, similar to Hill Climbing's local-optimum issues

Properties

PropertyResult
CompletenessNo - can stall in a local minimum of conflicts (analogous to Hill Climbing's local optima)
Optimality / Solution QualityReturns a fully conflict-free solution if found; no concept of "path cost" to optimize beyond satisfying constraints
Empirical performanceSurprisingly effective on many large, randomly-generated CSPs - often outperforms systematic search
✓ Advantages
  • Extremely fast in practice on many large CSP instances (e.g., million-queens)
  • Simple to implement, O(1)-ish per-step cost for sparse constraint graphs
  • Naturally an "anytime" repair strategy - can be restarted or resumed easily
✗ Disadvantages
  • Not complete - provides no guarantee of finding a solution even if one exists
  • Can get stuck in local minima with persistent conflicts, just like Hill Climbing
  • Performance can degrade sharply near the "phase transition" region of tightly-constrained problems

Applications

  • Large-scale scheduling problems (e.g., the Hubble Space Telescope's observation scheduler famously used Min-Conflicts)
  • N-Queens and similar large constraint puzzles
  • Real-time resource allocation where a fast, "good enough" repair beats slow, perfect search
🔑 Key Points
  • Min-Conflicts is local search applied to CSPs - repairs conflicts iteratively from a complete assignment.
  • Surprisingly effective on large CSPs (million-queens), but incomplete - no solution guarantee.
  • Conceptually parallels Hill Climbing: subject to the same "local minimum" risk.

Interview & Exam Questions

Q. Why might Min-Conflicts solve the million-queens problem faster than Backtracking Search, despite not being complete?

Backtracking builds a solution incrementally and can waste enormous effort exploring and undoing many partial assignments before finding a valid configuration, especially as N grows. Min-Conflicts instead starts from a complete assignment and only needs a small number of local repairs - empirically, for N-Queens, the number of conflicts tends to decrease very quickly with each repair step, regardless of how large N is, giving roughly constant-time-per-queen performance in practice, even though no formal completeness guarantee exists.

Q. What failure mode does Min-Conflicts share with Hill Climbing, and why?

Both can get stuck in a local minimum - for Min-Conflicts, a state where every possible single-variable reassignment fails to reduce the total conflict count, even though a globally conflict-free solution exists elsewhere in the assignment space. This mirrors Hill Climbing's local-maximum trap, since both algorithms make only locally greedy improving moves without any mechanism (like random restarts or simulated-annealing-style randomness) built in by default to escape such traps.

📋 Module 4 - Complete Summary

Module 4 covered two pillars of multi-constraint/multi-agent reasoning. Game playing ran from game theory's Nash Equilibrium foundations through Minimax (optimal but exponential), Alpha-Beta Pruning (same result, O(b^(m/2)) best case via α/β cutoffs), Monte Carlo Tree Search (simulation-based, no evaluation function needed - powers AlphaGo), and extended to stochastic games (Expectimax for chance nodes) and partially observable games (belief states, mixed strategies, bluffing). Constraint Satisfaction Problems reframed search as variable-assignment under constraints, solved via Backtracking Search (complete, boosted by MRV/Degree/LCV heuristics and forward checking/AC-3 propagation) or Min-Conflicts local search (incomplete but remarkably fast on large, loosely-constrained problems like million-queens).