Snakes and Ladders looks like a board game, but it is really a shortest-path problem in disguise. Once you see each square as a node and each die roll as an edge, the answer falls out of plain BFS.
Problem. You start on square 1 of an n x n board numbered in boustrophedon (zig-zag) order, ending
on square n*n. On each turn you roll a die and move forward 1 to 6 squares. Some squares hold a
ladder (jump up) or a snake (slide down); landing on one moves you instantly to its destination.
Return the fewest dice rolls to reach the last square, or -1 if it is impossible.
Example (3x3 board): ladder 2→8, snake 7→4. Answer is 2 — roll to square 2, take the ladder to 8,
then roll from 8 to 9.
The slow way first
You could try every sequence of rolls and keep the shortest that reaches the end. But the number of roll sequences explodes exponentially, and many of them revisit the same square. Tracking "what is the fewest rolls to reach this square" by brute force re-computes the same answers over and over.
The question to ask: what does each turn really do? A single roll takes you from one square to one of the next six squares (after applying any snake or ladder). That is exactly a graph edge.
The idea: squares are nodes, rolls are edges
Build the graph implicitly. From square s, the neighbors are s+1, s+2, ..., s+6, except a neighbor
that holds a snake or ladder is replaced by its destination. Every edge costs one roll, so the fewest
rolls to reach the goal is the shortest path in an unweighted graph — and BFS solves that.
Because BFS visits nodes in order of distance, the first time we dequeue the final square, its level is guaranteed to be the minimum number of rolls.
Walk through it
Step through the animation. Square 1 is the BFS root at distance 0. One roll expands to squares 3..8 — landing on 2 takes the ladder to 8, landing on 7 takes the snake to 4. Square 8 is now reachable in one roll, so a single roll from 8 reaches square 9. We dequeue 9 at distance 2, and that is the answer.
Pseudocode
queue = [(square 1, rolls 0)]
visited = {1}
while queue is not empty:
square, rolls = pop front of queue
if square is the last square:
return rolls
for nxt in square+1 .. min(square+6, last):
dest = the snake/ladder target of nxt, else nxt itself
if dest not visited:
mark dest visited
add (dest, rolls + 1) to the queue
return -1 # goal can never be reachedThe Python solution
def snakes_and_ladders(board):
n, target = len(board), len(board) * len(board)
queue = [(1, 0)] # (square, rolls)
visited = {1}
while queue:
square, rolls = queue.pop(0)
if square == target:
return rolls
for nxt in range(square + 1, min(square + 6, target) + 1):
dest = jump[nxt] if nxt in jump else nxt
if dest not in visited:
visited.add(dest)
queue.append((dest, rolls + 1))
return -1queueholds(square, rolls)pairs — a standard BFS frontier ordered by distance.visitedstops us from re-expanding a square, which is what keeps BFS linear.- The
for nxtloop enumerates the six edges of one die roll, capped at the final square. dest = jump[nxt] ...applies a snake or ladder by redirecting the landing square.- The first dequeued square equal to
targetreturns the fewest rolls, because BFS dequeues in distance order.
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (all roll sequences) | exponential (moderate) | re-explores squares endlessly |
| BFS (this solution) | O(n²) (slow) | each square enqueued once, 6 edges each |
O(n²) (slow)There are n² squares and at most six outgoing edges per square, so BFS does O(n²) work. The visited
set and queue each hold up to n² squares, giving O(n²) space.
When this pattern shows up
Whenever a problem asks for the fewest moves / shortest number of steps and every move costs the same, reach for BFS. Word Ladder, Open the Lock, Minimum Knight Moves, and Snakes and Ladders are all the same move: model states as nodes, transitions as equal-cost edges, and BFS by layer.
Apply the snake or ladder to the destination square, not the square you rolled — and mark dest (not
nxt) as visited. Forgetting the redirect, or visiting the pre-jump square, makes BFS revisit nodes and
return a wrong count.
Practice
On the 3x3 board with ladder 2→8 and snake 7→4, why is the answer 2 rolls and not 1?
1. Why does BFS give the fewest dice rolls?
2. What does one edge in this graph represent?
3. When a roll lands on a ladder or snake square, which square do we enqueue?
4. What is the time complexity of the BFS solution on an n x n board?