Recursion and computational thinking · A level · OCR H446 2.1.1, AQA 7517 4.1.1.15, Eduqas A500QS 1.3 · about 30 min
Model a maze, solve it by recursive backtracking, and drive the robot out along the route.
[1 mark]In the maze project, what is the base case that ends a call of solve with success?
[1 mark]What does the visited set do in the backtracking search?
[1 mark]What does this program print?
MAZE = ["S.#",
"#.#",
"..G"]
visited = set()
path = []
def solve(r, c):
if r < 0 or r > 2 or c < 0 or c > 2:
return False
if MAZE[r][c] == "#" or (r, c) in visited:
return False
visited.add((r, c))
path.append((r, c))
if MAZE[r][c] == "G":
return True
for dr, dc in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
if solve(r + dr, c + dc):
return True
path.pop()
return False
solve(0, 0)
print(path)[(0, 0), (0, 1), (1, 1), (2, 1), (2, 2)]
Trying right, down, left, up: right to (0, 1), down to (1, 1), down to (2, 1), then right to G at (2, 2). No dead end is met.
[1 mark]Which details did the maze model leave out, to be handled by the driving code?
Tick every answer that is true.
[1 mark]Why does a backtracking search not always find the shortest route?
Write a recursive function solve(row, col) for the maze above, following the five rules, with MAZE as the list of five strings, a set visited and a list path.
- row and col are whole numbers; the grid runs from 0 to 4 in each.
- solve returns True if the goal can be reached from (row, col) without revisiting a cell, and False otherwise.
- A cell that is off the grid, a block or already visited returns False without printing anything.
- An open cell that fails in all four directions prints back from (<row>, <col>), for example back from (0, 2), after taking itself off path.
- Try the directions in the order up, right, down, left.
Call solve(4, 0), then print path: followed by every cell on path, each written (row, col) and separated by single spaces, starting path: (4, 0) (4, 1).
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
MAZE = ["...#G",
".###.",
".#...",
".#.#.",
"S...."]
visited = set()
path = []
def solve(row, col):
return False
solve(4, 0)The hint students can ask for: Write the checks that end a call straight away first: off the grid, a block, or a cell already visited. Then mark the cell and add it to the path. If it is the goal you are done; otherwise try the four directions in the order given, and stop as soon as one works. Only when all four fail do you take the cell back off the path and report it.
from bugbot import *
connect()
MAZE = ["...#G",
".###.",
".#...",
".#.#.",
"S...."]
visited = set()
path = []
def solve(row, col):
if row < 0 or row > 4 or col < 0 or col > 4:
return False
if MAZE[row][col] == "#" or (row, col) in visited:
return False
visited.add((row, col))
path.append((row, col))
if MAZE[row][col] == "G":
return True
for d_row, d_col in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
if solve(row + d_row, col + d_col):
return True
path.pop()
print(f"back from ({row}, {col})")
return False
solve(4, 0)
print("path:", " ".join(f"({r}, {c})" for r, c in path))
Any program that meets the task's checks is marked correct in the simulator; this is one way, not the only way.