Maze solving (backtracking)
Find a way from the top-left to the bottom-right corner: go forward, and at every dead end mark it and back up.
The maze is a table: 0 is an open cell and 1 a wall. Start at the top-left corner and try right, down, left and up
in turn:
- Time:
O(rows · cols) - Space:
O(rows · cols) - Horowitz–Sahni, chapter 3
A 5×5 maze; the branch on the right is tried first and hits a dead end (x), then the way along the bottom reaches the exit (o).
def solve_maze(grid):# 0 is open and 1 is a wall; find a way from the top-left to the bottom-right corner.rows, cols = len(grid), len(grid[0])board = [["█" if cell else "·" for cell in row] for row in grid]if grid[0][0] or grid[rows - 1][cols - 1]:return Falsereturn walk(board, 0, 0, rows, cols)def walk(board, r, c, rows, cols):if r < 0 or r >= rows or c < 0 or c >= cols or board[r][c] != "·":return Falseboard[r][c] = "o"if r == rows - 1 and c == cols - 1:return Truefor dr, dc in [(0, 1), (1, 0), (0, -1), (-1, 0)]:if walk(board, r + dr, c + dc, rows, cols):return Trueboard[r][c] = "x"return False
Start
The table is still empty.
Recursion tree
Filled orange = running call · Orange outline = still on the stack · Grey = finished
Local variables
Orange = changed in this step
grid list
Call stack
- solve_maze()line 1
Explanation
The idea
The maze is a table: 0 is an open cell and 1 a wall. Start at the top-left corner and try right, down, left and up
in turn:
- if the next cell is open and not seen yet, enter it (
o); - if no way forward is left from a cell, mark it as a dead end (
x) and step back.
This is depth-first search on the graph of cells; the call stack is the current path.
Cost
Each cell is entered at most once: O(rows × cols). The path found is not necessarily the shortest; for that, use
breadth-first search.
What to watch in the trace
- The table is the maze:
█walls,othe current path andxthe dead ends. The call tree shows the branches tried.