A*路径查找算法有时不';即使有路径也找不到(Python)

A*路径查找算法有时不';即使有路径也找不到(Python),python,algorithm,path-finding,a-star,Python,Algorithm,Path Finding,A Star,我在Python中创建了一个自定义路径a*寻路算法,但有时它甚至找不到最终节点的路径,即使有明确的路径。这是我的实现 # this is my Node class. I am representing the whole maze as a matrix and every cell # of that matrix is a Node Object class Node(): def __init__(self, i, j): self.i = i

我在Python中创建了一个自定义路径a*寻路算法,但有时它甚至找不到最终节点的路径,即使有明确的路径。这是我的实现

# this is my Node class. I am representing the whole maze as a matrix and every cell
# of that matrix is a Node Object

class Node():
    def __init__(self, i, j):
        self.i = i
        self.j = j
        self.isWall = False
        self.isOpen = None
        self.f = 0
        self.g = 0
        self.h = 0
        self.neighbors = []
        self.previous = None

    def __repr__(self):
        return f'< i = {self.i}, j = {self.j}, previous = {self.previous} >'

    def add_neighbors(self, grid, diagonal):
        i = self.i
        j = self.j

        if i > 0:
            self.neighbors.append(grid[i - 1][j])

        if i < len(grid) - 1:
            self.neighbors.append(grid[i + 1][j])


        if j > 0:
            self.neighbors.append(grid[i][j - 1])

        if j < len(grid) - 1:
            self.neighbors.append(grid[i][j + 1])

        if diagonal:
            # for diagonal neighbors

            # down and right
            if i < len(grid) - 1 and j < len(grid) - 1:
                self.neighbors.append(grid[i + 1][j + 1])

            # up and right
            if i > 0 and j < len(grid) - 1:
                self.neighbors.append(grid[i - 1][j + 1])

            #down and left
            if i < len(grid) - 1 and j > 0:
                self.neighbors.append(grid[i + 1][j - 1])

            #up and left
            if i > 0 and j > 0:
                self.neighbors.append(grid[i - 1][j - 1])
下面是我正在使用的HScore函数

# HScore function

def getHScore(node, endNode):
    return sqrt(abs(node.i - endNode.i)**2 + abs(node.j - endNode.j)**2)

下面是实际的算法实现

# A* PATHFINDING ALGORITHM

def aStar(start_node, end_node):
    # node.f = node.g + node.h
    # node.g = distance of current node from the starting node
    # node.h = distance of current node from the end node

    start_node.g = 0
    start_node.h = getHScore(start_node, end_node)
    start_node.f = start_node.g + start_node.h
    open_set = [start_node]
    closed_set = []

    if start_node.isWall:
        print("The start node is a wall")
        return

    while True:
        
        if len(open_set) < 1:
            print('No Solutions Found')
            break

        current_node = open_set[0]

        for node in open_set:
            if node.f < current_node.f:
                current_node = node
                current_node.isOpen = True

        # print(f'current_node = {current_node.i, current_node.j}', end = " ")

        if current_node == end_node:
            temp = end_node
            path.append(temp)

            while temp.previous is not None:
                path.append(temp.previous)
                temp = temp.previous

            print("DONE")
            colorFinalPath(main_grid)
            break

        # current_node.isPath = True
        current_node.isOpen = False

        open_set.remove(current_node)
        closed_set.append(current_node)

        for neighbor in current_node.neighbors:
            # assuming 1 as the distance btw two neighbouring points that aren't diagonally
            # neighbors

            # need to add 1.14 if neighbor is diagonal. add propery to node class to check if neighbor is diagonal

            if neighbor in closed_set:
                continue

            tempG = current_node.g + getHScore(current_node, neighbor)

            if neighbor not in open_set and not neighbor.isWall:
                neighbor.g = tempG
                open_set.append(neighbor)
                neighbor.isOpen = True
                neighbor.previous = current_node

            if tempG >= neighbor.g:
                continue # there is no better path
            
            # neighbor was found in the open set, so we check if we can get to it in 
            # a better way as tempG is now less than neighbor.g

            neighbor.previous = current_node
            neighbor.g = tempG
            neighbor.h = getHScore(neighbor, end_node)
            neighbor.f = neighbor.g + neighbor.h

        show_steps(main_grid, start_node, end_node)

#A*寻路算法
def aStar(开始节点、结束节点):
#node.f=node.g+node.h
#node.g=当前节点与起始节点的距离
#node.h=当前节点到结束节点的距离
开始节点。g=0
start_node.h=getHScore(start_node,end_node)
start_node.f=start_node.g+start_node.h
打开\u集=[开始\u节点]
闭合_集=[]
如果启动node.isWall:
打印(“开始节点是墙”)
返回
尽管如此:
如果len(打开_集)<1:
打印('未找到解决方案')
打破
当前\u节点=打开\u集[0]
对于开放集合中的节点:
如果node.f=邻居.g:
继续,没有更好的路了
#邻居在开放的集合中被发现,所以我们检查是否可以在中找到它
#作为tempG的一个更好的方法现在比邻居的更少
neighbor.previous=当前_节点
邻居.g=tempG
h=getHScore(邻居,结束节点)
邻居.f=邻居.g+邻居.h
显示步骤(主网格、开始节点、结束节点)
一些屏幕截图 在第三幅图中,在起始节点(左上)和结束节点(右下)之间显然有一条路径,但它没有找到任何解决方案

请告诉我我的实现有什么问题。谢谢你的帮助


我在这段代码中看到了一些问题:

tempG = current_node.g + getHScore(current_node, neighbor)

if neighbor not in open_set and not neighbor.isWall:
    neighbor.g = tempG
    open_set.append(neighbor)
    neighbor.isOpen = True
    neighbor.previous = current_node

if tempG >= neighbor.g:
    continue # there is no better path
  • 当邻居是一面墙时,你应该立即跳过它。因此,在顶部添加:

      if neighbor.isWall:
          continue
    
    这也意味着您可以从
    中删除墙检查(如果您已经有了

  • 当您第一次设置
    g
    组件时,即执行中间部分时,检查没有更好路径的条件也将为真。这不应该发生。因此,将
    if
    更改为
    elif

      if neighbor not in open_set:
           # ... etc ...
      elif tempG >= neighbor.g:
          continue # there is no better path
    
  • 您的
    make_grid
    代码可以将结束节点标记为墙。您不会拒绝这种情况,然后您的代码将
    继续
    ,并将其作为邻居跳过以放入开放集。从您的图像中不清楚是否发生了这种情况,因为您将结束节点涂成了蓝色

这样,问题就不那么严重了,但有时会对同一个节点多次调用
getHScore
。显然,该函数将为每个调用返回相同的值。所以你可以改进一下。例如,通过在
if
条件下移动该行:

if neighbor.h == 0:
    neighbor.h = getHScore(neighbor, end_node)

我不知道这是否是有意的,但斜踏步的成本是2(1²+1²),而且它与两步走到同一个广场没有任何优势。这是一个很小的细节,因为您将首先通过对角步骤访问这些节点,然后以相同的代价忽略路径。

这是整个
节点
类吗?可能是一个愚蠢的问题,但您启用了对角吗?@harold是的,这是整个节点class@NathanWride是的。在node类中,我添加了对角邻域。你能展示你迭代和设置节点的代码吗?我对我的代码进行了修改,现在它运行得更快,因为它跳过了墙,但当显然有墙的时候,它再次没有给出解决方案。太长了,我将把它分为“当前_节点中的邻居”组。邻居:如果邻居在封闭的_集中或邻居。isWall:continue tempG=current_节点。g+1如果邻居不在开放的_集中:neighbor.g=tempG open_集。append(neighbor)neighbor.isOpen=True neighbor.previous=current_node elif tempG>=neighbor.g:继续#没有更好的路径``part 1 endpart 2 neighbor.previous=current_node neighbor.g=tempG if neighbor.h==0:neighbor.h=getHScore(邻居,结束节点)邻居.f=邻居.g+邻居.h显示步骤(主网格,开始节点,结束节点)我在第三张图片中对网格进行了编码,但无法重现问题。它找到了路径。请看。我看到您的代码可以在节点中为目标节点生成一堵墙,您在图像中没有指出这一点。这可能是一个原因。哦,知道了。谢谢。错过了这么简单的一点
if neighbor.h == 0:
    neighbor.h = getHScore(neighbor, end_node)