A *路径查找算法有时即使在存在路径的情况下也找不到路径Python

问题描述

我用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])

反复浏览并设置节点

def make_grid(length):
    main_grid = []
    for i in range(length):
        lst = []
        
        for j in range(length):
            node = Node(i,j)

            # 30 % chance that the current node will be set as a wall
            if random.randrange(1,101) > 70 and i != 0 and j != 0: node.isWall = True

            lst.append(node)

        main_grid.append(lst)


    for i in range(length):
        for j in range(length):
            main_grid[i][j].add_neighbors(main_grid,diagonal = True)
 

    return main_grid

# Below is how the above function 'make_grid' is called

# making the grid
grid_len = 25
main_grid = make_grid(grid_len)
path = [] # to reconstruct the optimal path

下面是我正在使用的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)

一些屏幕截图 在第三张图中,显然在起始节点(左上)和结束节点(右下)之间有一条路径,但是找不到任何解决方案。

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

AStar Algo Outputs. Blue line is the path found. Red spots are closed nodes. Green spots are open nodes

解决方法

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

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
    

    这也意味着您可以从已经拥有的if上取下墙面支票

  • 当您第一次设置g组件(即执行中间部分)时,检查路径是否存在更好的条件也将成立。这不应该发生。因此,将if更改为elif

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

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

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

我不知道这是否有意,但对角台阶的成本为2(1²+1²),与步行到同一广场的2步相比没有优势。这是一个很小的细节,因为您将首先通过对角线步骤访问那些节点,然后忽略具有相同成本的路径。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...