Problem
You have an n×n board where squares are numbered 1 to n² starting from the bottom-left corner and winding in a boustrophedon (S-shape) pattern — left to right on odd rows from the bottom, right to left on even rows. On each turn you roll a six-sided die and advance 1–6 squares; if the square you land on has a snake or ladder, you immediately teleport to its destination. Find the minimum number of moves to reach square n², or return -1 if it's impossible.
- Input:
board = [[-1,-1,-1,-1,-1,-1],[-1,-1,-1,-1,-1,-1],[-1,-1,-1,-1,-1,-1],[-1,-1,2,-1,-1,-1],[-1,-1,-1,-1,-1,-1],[-1,4,-1,-1,-1,-1]] - Output:
4 - Explanation: Roll 2 (land on sq 2 → teleport to sq 4 via the ladder at board[5][1]=4), then continue with optimal rolls to reach square 36 in 4 total moves.
Counter-example — board[row][col] = -1 means no snake or ladder on that square; only non-negative-one values trigger teleportation.
Intuition
Each square is a node in a graph, and each die roll is an edge to the next 1–6 reachable squares (after any teleportation). Because every edge costs exactly one move, BFS naturally finds the shortest path from square 1 to square n². The main challenge isn't the algorithm — it's correctly translating a square number into its row and column on the boustrophedon-numbered board.
Solution — BFS with Coordinate Conversion
Flatten the problem: treat each square as a node in an unweighted graph and run BFS from square 1. For every square popped from the queue, try all six die outcomes; if the destination has a snake or ladder, jump to its endpoint before enqueuing.
- Write a helper that converts square number
sto(row, col)on the board: computeidx = s - 1, thenrow_from_bottom = idx // nandcol = idx % n; ifrow_from_bottomis odd, reversecolton - 1 - col; finally,row = n - 1 - row_from_bottom. - Initialize a
visitedset containing square 1 and a queue with(square=1, moves=0). - While the queue is non-empty, dequeue
(square, moves). - For each roll from 1 to 6, compute
next_sq = square + roll; stop if it exceeds n². - Convert
next_sqto board coordinates and, if the cell is not -1, overwritenext_sqwith the teleport destination. - If
next_sq == n², returnmoves + 1; otherwise, if unvisited, mark it visited and enqueue(next_sq, moves + 1). - Return -1 if the queue empties without reaching n².
1from collections import deque
2
3def snakesAndLadders(board: list[list[int]]) -> int:
4 n = len(board)
5
6 def square_to_rc(s: int) -> tuple[int, int]:
7 idx = s - 1
8 row_from_bottom = idx // n
9 col = idx % n
10 if row_from_bottom % 2 == 1: # odd rows read right-to-left
11 col = n - 1 - col
12 row = n - 1 - row_from_bottom # flip so row 0 is at the top
13 return row, col
14
15 visited = {1}
16 queue = deque([(1, 0)]) # (current_square, moves_taken)
17
18 while queue:
19 current_sq, moves = queue.popleft()
20
21 for roll in range(1, 7):
22 next_sq = current_sq + roll
23 if next_sq > n * n:
24 break # die rolls are sequential; no need to try larger values
25
26 row, col = square_to_rc(next_sq)
27 if board[row][col] != -1: # snake or ladder present
28 next_sq = board[row][col] # teleport to its destination
29
30 if next_sq == n * n:
31 return moves + 1
32
33 if next_sq not in visited:
34 visited.add(next_sq) # mark when enqueuing to prevent duplicates
35 queue.append((next_sq, moves + 1))
36
37 return -1Time: O(n²) — each of the n² squares is visited at most once.
Space: O(n²) — visited array and BFS queue each hold at most n² entries.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| BFS | O(n²) | O(n²) | Always — BFS is the canonical shortest-path method for unweighted graphs |
Common Mistakes
- Wrong boustrophedon direction: forgetting that odd rows from the bottom read right-to-left — without the
if rowFromBottom % 2 == 1: col = n - 1 - colflip, every other row maps to the wrong square. - Marking visited after dequeuing instead of enqueuing: the same square can be added to the queue many times before it's processed, causing exponential slowdown; always mark visited immediately when you push to the queue.
- Applying teleportation when the cell is -1: only teleport when
board[row][col] != -1; treating -1 as a teleport to square -1 causes an index-out-of-bounds or silent wrong answer. - Off-by-one in square numbering: squares are 1-indexed (1 to n²) but the array is 0-indexed —
idx = s - 1before dividing bynis essential. - Skipping the teleport destination check for n²: after teleporting, check if the new square equals n²; some solutions only check the die-roll destination and miss a ladder that leads directly to the finish.
Related Problems
rotting-oranges— BFS on a grid where each cell's state propagates level by level, same "minimum steps" framing01-matrix— multi-source BFS to find the shortest distance from each cell to the nearest zeroword-ladder— BFS on an implicit graph where nodes are strings and edges are one-character transformationsnumber-of-islands— BFS/DFS to explore connected components in a gridflood-fill— BFS/DFS spreading from a source cell to all reachable neighbors