【问题标题】:Maze pathfinding implementation (BFS) not giving correct path [closed]迷宫寻路实现(BFS)没有给出正确的路径[关闭]
【发布时间】:2021-04-16 10:55:57
【问题描述】:

我正在尝试用球找到迷宫的最短路径:球一直滚动直到撞到墙上。我使用 Dijkstra 的算法,使用heapq 作为优先级队列。但是,我得到了一条非最佳路径。

这是我的示例输入代码:

maze = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
        [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
        [0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0],
        [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0],
        [0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0],
        [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0],
        [0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0],
        [0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
        [1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
        [0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
        [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0],
        [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1],
        [1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
        [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
        [0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0],
        [0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0],
        [0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
        [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

start = (0, 0)
end = (22, 22)

def shortestDistance(maze: List[List[int]], start: List[int], destination: List[int]):
    start, destination = tuple(start), tuple(destination)
    row, col = len(maze), len(maze[0])
    moves = [(-1, 0), (0, 1), (0, -1), (1, 0)]
    dstr = ['u', 'r', 'l', 'd']

    class Point:
        def __init__(self, distance, coordinates, directions):
            self.distance = distance
            self.coordinates = coordinates
            self.directions = directions

        def __eq__(self, p):
            if self.distance == p.distance:
                return self.__lt__(self, p)

            return self.distance - p.distance

        def __lt__(self, p):
            return len(self.directions) - len(p.directions)


    heap = [(Point(0, start, ""))]
    visited = set()
    while heap:
        point = heapq.heappop(heap)
        dist = point.distance
        node = point.coordinates
        directions = point.directions

        if node in visited: continue
        if node == destination:
            return directions

        visited.add(node)

        for idx, move in enumerate(moves):
            dx, dy = move
            newX = node[0]
            newY = node[1]
            distance = dist
            newDirections = directions
            while 0 <= newX + dx < row and 0 <= newY + dy < col and maze[newX + dx][newY + dy] == 0:
                newX += dx
                newY += dy
                distance += 1
                if (newX, newY) == destination:
                    break

            if (newX, newY) not in visited:
                heapq.heappush(heap, Point(distance, (newX, newY), newDirections + dstr[idx]))

    return "Impossible"


path = shortestDistance(maze, start, end)
print(path)

这个想法是比较距离,如果相等,则选择方向变化较少的路径。

我目前正在将rdrludlrdrudludldldr(即右下右左-...)作为输出,但在索引 2 处找到的序列“rl”没有意义:“右”不应该是后跟“左”也不应该“上”后跟“下”,反之亦然。这样的顺序显然不是最优的,因为这两个动作中的第一个可以省略,以使球在相同的位置并移动更短的距离。

这个迷宫的预期输出是drururdrdrurdrd

为什么我没有得到最短路径?

【问题讨论】:

  • 尝试创建一个尽可能小的失败示例,然后开始调试。
  • 虽然您的建议可用于测试,但输出清楚地表明还有其他问题,不幸的是。我无法理解算法背后的逻辑来修复它,我确信这是某个地方的一个小错误。
  • 就像您之前的问题一样,您有未定义的变量。请问,在 Stack Overflow 上发布之前,我们能否要求您仔细检查您的代码是否存在这些明显的错误?
  • 什么是未定义的变量好先生?感谢您在 Stack Overflow 上关注我以尝试解决我的问题,我只希望对实际算法如此专注的人出现在这里。
  • x, y 没有定义。我已经在你之前的问题中提到了这一点。

标签: python algorithm breadth-first-search path-finding maze


【解决方案1】:

问题是__lt__ 函数没有做它应该做的事情。

self 被认为小于p 时,它应该返回一个布尔值。当您当前返回一个整数结果时,它通常是非零的,您会遇到这样的情况:一对 (p, q) 点将 p

你可以这样定义它:

def __lt__(self, p):
    return ((self.distance, len(self.directions), self.directions) < 
          < (p.distance, len(p.directions), p.directions)) 

通过此更改,返回的路径为

rdrdldldrdr

简化

您可以使用命名元组,而不是创建类Point,这使一切变得更容易(并且更快)。您只需要更改“属性”的顺序,以便这些点以所需的方式进行比较,即 directions 应该在 coordinates 之前,并且方向字符串的长度应该有自己的属性:

from collections import namedtuple

# change order of properties so comparison works as intended
Point = namedtuple("Point", "distance, length, directions, coordinates")

然后在您调用Point的位置进行适当的更改:

heap = [Point(0, 0, "", start)]
# ...
heapq.heappush(heap, Point(distance, len(newDirections) + 1, newDirections + dstr[idx], (newX, newY)))

【讨论】:

  • 太好了,非常感谢(再次)!我知道我可能会在这里扩大您的热情好客,但您能告诉我(请不要这样做),为什么我不会得到另一个示例数组的正确结果。把它放在评论里有点难,所以我把它上传到这里。 pastebin.com/8uyBgmp7
  • 我得到了drururdrdrurdrd 作为输出 - 虽然前 7 或 8 个方向很好,但接下来的方向基本上会导致死胡同。我相信它应该以drururd 开头,但随后它会上升而不是下降(至少我认为它应该下降,通过尝试手动找到最佳路径)。起点和终点相同。
  • 如果你认为解不是最优的,那么最优解是什么?我觉得很好。
  • 我在阅读了较短的方向(更少的转弯)应该在距离相等时获得优先权后进行了更新。不过,这不会改变本案的结果。
  • 很高兴听到。如果您还有其他问题我可以提供帮助,请联系我(在评论中使用@trincot),我会看看。无需赔偿。偶尔投赞成票已经很好了(但不要批量投票)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多