Whatever-First Search

Week 6, Monday

February 9, 2026

Recap: The Maze Explorer

Last week, we explored a maze using different containers:

Container Order Behavior
Bag Random Chaotic
Stack LIFO Go deep, backtrack
Queue FIFO Explore by distance

Today: What made this work, and where else can we use it?

The Key Insight

The algorithm structure is always the same.

Three things change:

  1. The bag: What state do we process next?
  2. The neighbors: What’s adjacent to the current state?
  3. The bookkeeping: What do we track about each state?

Designing Your Search: A Checklist

Question Your answer
What is a state?
What are the neighbors of a state?
What bag should I use?
What do I need to track?
When do I mark visited?
When do I stop?

Choosing the Bag

Bag Type Name Behavior
Stack Depth-First Search Go deep, backtrack
Queue Breadth-First Search Explore by distance
Priority Queue Best-First Search Explore by “goodness”

Choosing the Bookkeeping

Question What to track
“Can I reach X?” visited (set)
“How far is X?” distance (dict: state → int)
“What’s the path to X?” parent (dict: state → state)
“When did I discover X?” discovery_time (dict: state → int)
“When did I finish X?” finish_time (dict: state → int)

The question determines the data structures.

When to Mark Visited?

Two choices:

# Option A: Mark when adding to bag
if neighbor not in visited:
    visited.add(neighbor)
    bag.put(neighbor)

# Option B: Mark when removing from bag
current = bag.get()
if current not in visited:
    visited.add(current)

Option A (our version today): Each state enters bag once.

Option B: Each transition adds to bag once (so states can appear multiple times).

What Is a “Thing”? (State)

The “thing” in the bag is whatever describes where you are:

Domain State (the “thing”)
Maze Room number
Grid (row, col) position
Social network Person
Tower of Hanoi Configuration of all disks
Word ladder Current word

State = everything needed to know “where am I now?”

What Are “Neighbors”?

The neighbors(state) function says what’s reachable in one step:

Domain Neighbors of state
Maze Rooms connected to current room
Grid Cells adjacent to (row, col)
Social network Friends of current person
Tower of Hanoi Configurations after one valid move
Word ladder Words differing by one letter

The problem defines what “one step” means.

An Example Problem

How do we find the shortest path from S to E in a grid?

S E

Let’s fill out our checklist…

Step 1: What is a state?

Question Answer
What is a state? (row, col) position
What are the neighbors?
What bag?
What do I track?
When mark visited?
When do I stop?

A state is a cell: (row, col).

Step 2: What are the neighbors?

Question Answer
What is a state? (row, col) position
What are the neighbors? 4-connected
What bag?
What do I track?
When mark visited?
When do I stop?
C X X X X

From (r, c), neighbors are (r±1, c) and (r, c±1).

Step 3: What bag?

We want shortest paths.

The distance from A to B is the minimum number of steps.

43234 32123 21012 32123 43234

How do we explore in order of distance?

Why Queues Give Distances

When we use a queue:

  • We process all distance-1 cells before any distance-2 cells
  • We process all distance-2 cells before any distance-3 cells
  • And so on…

This is Breadth-First Search (BFS).

BFS Gives Shortest Paths

Observe: When BFS discovers a state, the recorded distance is the shortest path distance.

Why?

  • BFS explores in order: all distance-1 before any distance-2, etc.
  • If there were a shorter path, we would have found it earlier!

Step 3: What bag? (answered)

Question Answer
What is a state? (row, col) position
What are the neighbors? 4-connected adjacent cells
What bag? Queue (FIFO) → BFS
What do I track?
When mark visited?
When do I stop?

Queue gives us shortest paths!

Step 4: What do I track?

Question Answer
What is a state? (row, col) position
What are the neighbors? 4-connected adjacent cells
What bag? Queue (FIFO) → BFS
What do I track? distance dict, parent dict
When mark visited?
When do I stop?
  • distance: how far is each cell?
  • parent: how do I get there? (for path reconstruction)

Step 5: When mark visited?

Question Answer
What is a state? (row, col) position
What are the neighbors? 4-connected adjacent cells
What bag? Queue (FIFO) → BFS
What do I track? distance dict, parent dict
When mark visited? When adding to queue
When do I stop?

Mark visited when adding → each cell enters queue once.

Step 6: When do I stop?

Question Answer
What is a state? (row, col) position
What are the neighbors? 4-connected adjacent cells
What bag? Queue (FIFO) → BFS
What do I track? distance dict, parent dict
When mark visited? When adding to queue
When do I stop? Goal found (or queue empty)

Checklist complete! Now let’s write the code.

BFS on a Grid

from collections import deque

def bfs(grid, start, end):
    rows, cols = len(grid), len(grid[0])
    distance = {start: 0}
    parent = {start: None}
    queue = deque([start])

    while queue:
        r, c = queue.popleft()
        if (r, c) == end:
            return distance, parent
        for nr, nc in neighbors(r, c, rows, cols):
            if (nr, nc) not in distance:
                distance[(nr, nc)] = distance[(r, c)] + 1
                parent[(nr, nc)] = (r, c)
                queue.append((nr, nc))

    return distance, parent

Each arrow points to parent: the cell that discovered it.

Reconstructing the Path

def get_path(parent, end):
    # Follow parent pointers, pushing onto stack
    stack = []
    current = end
    while current is not None:
        stack.append(current)
        current = parent[current]

    # Pop from stack to reverse the path
    path = []
    while stack:
        path.append(stack.pop())
    return path

Use a stack to reverse the parent pointers!

The Neighbor Function

def grid_neighbors(r, c, rows, cols):
    """4-connected neighbors on a grid."""
    for dr, dc in [(-1,0), (1,0), (0,-1), (0,1)]:
        nr, nc = r + dr, c + dc
        if is_valid(nr, nc, rows, cols):
            yield (nr, nc)

def is_valid(r, c, rows, cols):
    return 0 <= r < rows and 0 <= c < cols

Two design decisions:

  • Candidates: 4-connected? 8-connected? Knight moves?
  • Validity: In bounds? Not a wall? Climbable?

Love Letters in the Mountains

Your Turn

Help Donkey find the shortest path to Dragon’s castle!

Complete the activity in PL to solve the puzzle!

The Story

Donkey must deliver a love letter to Dragon through mountainous terrain.

  • Start at village S in a valley
  • Deliver to Dragon’s castle E on a peak
  • Each step: move to adjacent cell
  • Constraint: Donkey can only climb one elevation level at a time!
aabqponm
abcryxxl
accszzxk
acctuvwj
abdefghi

(heights: a=0, b=1, …, z=25)

The Terrain Rules

From height h, you can step to a neighbor with height at most h + 1.

  • From a (height 0): can reach a or b
  • From c (height 2): can reach a, b, c, or d
  • From z (height 25): can reach anything!

This changes what “neighbors” means.

Part 1: Exploring the Valley

Question: Starting from S, how many locations can the messenger reach in at most 10 steps?

This is BFS with a step limit.

Part 2: Finding the Castle

Question: What is the shortest path from S to E?

This is BFS for shortest path.

(Stop when we reach E, return the distance.)

Part 3: The Scenic Route

Donkey wants to start from a valley—but which one?

Question: Which a cell has the shortest path to Dragon’s castle E?

A Clever Observation

Option 1: Run BFS from every a cell, take minimum. (Slow if there are many a cells!)

Option 2: Run BFS backwards from E.

  • Use reversed edges: if A→B exists, search B→A
  • Find all cells that can reach E
  • Check which a cell is closest

Reversing the Edges

Forward edge (A can reach B): - From height h, can step to height ≤ h + 1

Backward edge (who can reach me?): - From height h, can step to height ≥ h - 1

Same algorithm, different neighbor function!

The Power of Abstraction

Both problems use the same BFS template:

  1. Bag: Queue (for shortest paths)
  2. Neighbors: Defined by terrain rules
  3. Termination: Goal reached or all reachable

Only the neighbor function changes!

Neighbors Are Everywhere

Problem “State” Neighbors
Grid maze (row, col) Adjacent cells
Word ladder “COLD” Words 1 letter away
Tower of Hanoi Disk positions Valid moves
Rubik’s cube Cube state Single rotations
Social network Person Friends

If you can define neighbors, you can search.

Lab Preview

In lab this week, you’ll implement:

  • Tower of Hanoi game (state transitions)
  • Sliding window problems (queue applications)
  • Nearest smaller element (stack pattern)
  • Histogram max area (stack application)

What’s Next

  • Tuesday video: The Magic of O(1) Lookup — Dictionaries
  • Wednesday: Dictionary Puzzles — Two-Sum, anagrams, frequency counting