python - 重新访问 A* 搜索中访问过的节点

标签 python search graph nodes a-star

我正在尝试在定向运动中应用 A* 搜索来获取最佳路线。输入是两个文件 - 一个解释地形的图像文件和一个定义海拔的文本文件。我根据预设值计算地形难度,以定义穿越地形的速度。我还根据坡度定义了海拔难度(向下的坡度速度更快,反之亦然)。

地形和高程数据存储在矩阵(列表的列表)中。因此,输入是与 map 上的点相同的索引。提供了两个输入 - 例如:

start = [230,327]
end = [241,347]

问题是我的代码不断重新访问已访问队列中已存在的节点。节点定义如下:

class Node:
    def __init__(self,value,parent,start=[],goal=[]):
        self.children = []
        self.parent = parent
        self.value = value
        self.timeToGoal = 0.0000
        self.timeTravelled = 0.0000

        if parent:
            timeToParent = self.parent.timeTravelled
            [parentX, parentY] = parent.value
            [currentX, currentY] = self.value
            xDiff = abs(currentX - parentX)
            yDiff = abs(currentX - parentX)
            distance = 12.7627
            if xDiff == 0 and yDiff != 0:
                distance = 10.29
            elif xDiff != 0 and yDiff == 0:
                distance = 7.55
            # distanceFromParent = math.sqrt(((currentX - parentX) ** 2) - (currentY - parentY) ** 2)
            speedFromParent = 1.388 * calculateTerrainDifficulty( terrainMap[currentX][currentY]) * calculateElevationDifficulty(elevationMap[parentX][parentY], elevationMap[currentX][currentY], distance)
            timeTravelledFromParent = 0
            if speedFromParent != 0:
                timeTravelledFromParent = distance / speedFromParent
            else:
                "Error: Speed from Parent Cannot Be Zero"
            self.timeTravelled = timeToParent + timeTravelledFromParent
            self.path = parent.path[:]
            self.path.append(value)
            self.start = parent.start
            self.goal = parent.goal

        else:
            self.path = [value]
            self.start = start
            self.goal = goal

    def GetTime(self):
        pass

    def CreateChildren(self):
        pass

我还使用了 SubNode 类来定义函数,时间定义为到达自身的时间 + 毕达哥拉斯斜边到目标的距离:

class SubNode(Node):
    def __init__(self, value, parent, start=[], goal=[]):
        super(SubNode, self).__init__(value, parent, start, goal)
        self.timeToGoal = self.GetTime()

    def GetTime(self):
        if self.value == self.goal:
            return 0
        [currentX, currentY] = self.value
        [targetX, targetY] = self.goal
        parentTime = 0
        if self.parent:
            parentTime = self.timeTravelled
        heuristicTime = 99999.99
        # Pythagorean Hypotenuse - Straight-line Distance
        distance = math.sqrt(((int(currentX) - int(targetX)) ** 2) + (int(currentY)- int(targetY)) ** 2)
        speed = 1.38 * calculateTerrainDifficulty(terrainMap[currentX][currentY])
        if speed != 0:
            heuristicTime = distance / speed
        heuristicTime=heuristicTime+parentTime
        return heuristicTime


    def CreateChildren(self):
        if not self.children:
            dirs = [-1, 0, 1]
            [xVal, yVal] = self.value
            for xDir in dirs:
                newXVal = xVal + xDir
                if newXVal < 0 or newXVal > 394: continue
                for yDir in dirs:
                    newYVal = yVal + yDir
                    if ((xVal == newXVal) and (yVal == newYVal)) or (newYVal < 0 or newYVal > 499) or (
                        calculateTerrainDifficulty(terrainMap[newXVal][newYVal]) == 0):
                        continue
                    child = SubNode([newXVal, newYVal], self)
                    self.children.append(child)

A* 搜索类别定义如下。您可以看到我已将条件放在那里以确保不会重新访问节点,并且当我将打印放在那里时,我可以看到多次满足条件。

class AStarSearch:
    def __init__(self, start, goal):
        self.path = []
        self.visitedQueue = []
        self.priorityQueue = PriorityQueue()
        self.start = start
        self.goal = goal

    def Search(self):
        startNode = SubNode(self.start, 0, self.start, self.goal)
        count = 0
        self.priorityQueue.put((0, count, startNode))
        while (not self.path and self.priorityQueue.qsize()):
            closestChild = self.priorityQueue.get()[2]e
            closestChild.CreateChildren()
            self.visitedQueue.append(closestChild.value)
            for child in closestChild.children:
                if child.value not in self.visitedQueue:
                    count += 1
                    if not child.timeToGoal:
                        self.path = child.path
                        break
                    self.priorityQueue.put((child.timeToGoal, child.value, child))
        if not self.path:
            print("Not possible to reach goal")
        return self.path

由于某种原因,我的程序不断重新访问某些节点(正如我在打印访问队列时从输出中看到的那样。我该如何避免这种情况?

[[230, 327]、[231, 326]、[229, 326]、[231, 325]、[231, 328]、[229, 328]、[231, 327], [229, 327], [231, 327], [229, 327], [229, 325], [231, 324], [230, 323], [231, 329 ], [229, 329], [231, 327], [229, 327], [229, 324], [231, 330], [231, 323], [229, 330], [229, 331]]

我面临的另一个问题是:

TypeError: unorderable types: SubNode() < SubNode()

有没有一种方法可以在不改变 python 优先级队列的使用的情况下克服这个问题?

最佳答案

您需要添加对closestChild而不是其子项的测试:

closestChild = self.priorityQueue.get()[2]e
if closesChild.value not in self.visitedQueue:
    closestChild.CreateChildren()
    self.visitedQueue.append(closestChild.value)

否则,您可以说您访问了 n1,然后访问了 n2,两者都链接到节点 n3n3priorityqueue 中添加了两次,因此它被弹出两次,然后两次添加到 visitedQueue 中。

条件if child.value not in self.visitedQueue:对于加快速度很有用(通过保持较小的优先级队列),但不是必需的(因为priorityQueue中不必要的对象 解压时会被丢弃)。

关于您收到的错误:PriorityQueue 不支持自定义排序,而这正是您的优先级队列所需要的,因此您必须进行自定义排序。有一个 example here 。显然,您的 _get_priority 函数需要返回 timeTravelled 而不是 item[1]

编辑3:我们(tobias_k和我)首先说你需要为SubNode实现__eq__函数,以便python知道何时两个它们是相等的,但实际上并非如此,因为您仅将值存储在 self.visitedQueue 中。

关于python - 重新访问 A* 搜索中访问过的节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46892866/

相关文章:

javascript - 将变量从 python 传递到 javascript

python - 在python中自动处理e(科学)表示法中的数字

algorithm - 非二叉树搜索和插入

php - Elasticsearch 查询字符串中的空值

c# - 在 ASP.NET 中键入时显示搜索结果

algorithm - 具有相关顶点成本的二分选择

java - 表示具有未知节点数的图?

python - 如何计算作为字符串列表的 Pandas 列中的值?

python - 我使用 selenium 进行网络爬行,获取 url 时出现语法错误,请帮我找到原因

android - 结合条形图和折线图