Вместо ведения списка path
вы можете поддерживать словарь edge_to
, который отслеживает, какая из предыдущих вершин привела к посещению определенной вершины. Всякий раз, когда вы добавляете что-то в свою очередь, вы можете обновить edge_to
. Модифицированная версия вашей функции с использованием этого подхода выглядит следующим образом:
Coordinate = collections.namedtuple('Coordinate', ['x', 'y'])
def find_path(s, e):
directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
queue = collections.deque()
queue.append(s)
edge_to = {s: None}
while queue:
curr = queue.popleft()
if curr == e:
return path(edge_to, curr)
maze[curr.x][curr.y] = BLACK
for x, y in directions:
new_x, new_y = curr.x + x, curr.y + y
if new_x < 0 or new_y < 0 or new_x >= len(maze) or new_y >= len(maze[0]) or maze[new_x][new_y] == BLACK:
continue
c = Coordinate(new_x, new_y)
edge_to[c] = curr
queue.append(c)
Обратите внимание на вызов path(...)
, когда вы найдете свою конечную вершину. Эта функция просто строит список из словаря edge_to
:
def path(edge_to, end):
curr = end
res = []
while curr != None:
res.append(curr)
curr = edge_to[curr]
return list(reversed(res))
Для вашего заданного лабиринта, а также начальных и конечных координат мы получаем следующий вывод:
s = Coordinate(3, 0)
e = Coordinate(0, 3)
print(find_path(s, e))
Вывод
[Coordinate(x=3, y=0), Coordinate(x=2, y=0), Coordinate(x=2, y=1), Coordinate(x=1, y=1), Coordinate(x=1, y=2), Coordinate(x=0, y=2), Coordinate(x=0, y=3)]