Because a graph can have loops, if you do not remember where you have been you go back and forth between the same two nodes for ever. The cure is a seen set: you queue a node only if you have not seen it before.
def reachable(grid, r, c, seen):if not (0 <= r < len(grid) and 0 <= c < len(grid[0])):returnif grid[r][c] == "#" or (r, c) in seen:returnseen.add((r, c))for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):reachable(grid, r + dr, c + dc, seen)
"Is there a way from A to B?" is this walk itself: start at A, and if B is among the seen when the walk ends, there is a way. Extra links like teleport pads only add one more edge to the neighbour list; the walk stays the same.