递归寻路算法不断返回 None

Recursive pathfinding algorithm keeps returning None

为了在 2D 地图中找到路径,我在 Person 实例上调用 get_building_path(),但它一直返回 None。我不知道出了什么问题,因为我是 Python.

的新手

下面我提供了重现该问题所需的代码。我已经尝试了很多东西,但我仍然不明白为什么它一直返回 None:

from random import randint

width = 1400
height = 700
gridSize = 20
people = []
buildings = []
map = [['' for c in range(int(width/gridSize))] for r in range(int(height/gridSize))]

class Person():
    def __init__(self,row,col):
        self.row = row
        self.col = col
    def getMin(self,paths): # find shortest path
        if (len(paths) == 0): return [] # if nothing was found, return an empty list
        min = paths[0]
        for n in range(1,len(paths),1):
            if ((paths[n] != None and len(paths[n]) < len(min)) or min==[None]): # make sure [None] is not returned since that would be the shortest
                min = paths[n]
        return min
    def path_helper(self,visited,path,row,col,destR,destC): # destR and destC are the row and col of the target position
        if ((row,col) in visited or map[row][col] != 'road' or row < 0 or row > len(map)-1 or col < 0 or col > len(map[0])-1):
            return None # make sure the current position has not been visited, and is in bounds of the map
        path.append([row,col]) # add current position to the path
        visited.append((row,col)) # mark current position as visited
        if (row == destR and col == destC): # return the path if we found the destination
            return path
        others=[] # look in all four directions from the current position
        others.append(self.path_helper(visited,path[:],row-1,col,destR,destC))
        others.append(self.path_helper(visited,path[:],row+1,col,destR,destC))
        others.append(self.path_helper(visited,path[:],row,col-1,destR,destC))
        others.append(self.path_helper(visited,path[:],row,col+1,destR,destC))
        others.remove(None) # remove any path that did not find anything
        return self.getMin(others)
    def get_path(self,row,col):
        return self.path_helper([],[],self.row,self.col,row,col) #call to recursive helper function
    def get_building_path(self,type):
        all = []
        for b in buildings:
            if (b.type == type):
                all.append(b)
        target = all[randint(0,len(all)-1)] #get a random buildings of type 'type'
        return self.get_path(target.row,target.col)
class Building():
    def __init__(self,type,row,col):
        self.type = type
        self.row = row
        self.col = col

midrow = int(height/gridSize/2) #get midpoint of the map
midcol = int(width/gridSize/2)
people.append(Person(midrow+1,midcol+2))
for n in range(0,3,2): #add new buildings to buildings list, along with the map
    buildings.append(Building('house',midrow+n,midcol-2))
    map[midrow+n][midcol-2] = buildings[len(buildings)-1]
    buildings.append(Building('school',midrow+n,midcol-1))
    map[midrow+n][midcol-1] = buildings[len(buildings)-1]
    buildings.append(Building('workplace',midrow+n,midcol))
    map[midrow+n][midcol] = buildings[len(buildings)-1]
    buildings.append(Building('store',midrow+n,midcol+1))
    map[midrow+n][midcol+1] = buildings[len(buildings)-1]
    buildings.append(Building('restaurant',midrow+n,midcol+2))
    map[midrow+n][midcol+2] = buildings[len(buildings)-1]
for n in range(-2,3,1): #add roads to connect the buildings together
    map[midrow+1][midcol+n] = 'road'

testPath = people[0].get_building_path('house')
print(testPath)

如果您想直观地看到建筑物和道路的位置,这里有一张图片:

从左到右,建筑物是'house'、'school'、'workplace'、'store'、'restaurant'。

蓝色圆圈代表人物。

(左上角建筑物的位置为(17,33) (row,col)

几个问题:

  • others.remove(None) 仅删除第一次出现的 None
  • map[row][col] != 'road' 到达目标时将为 True,因此此测试应仅在 确认您尚未到达目标后进行。
  • rowcol 超出范围时,
  • map[row][col] != 'road' 可能会出错,因此您应该 首先 进行范围检查

所以path_helper应该更正为:

    def path_helper(self,visited,path,row,col,destR,destC):
        path.append([row,col])
        # next IF should come before the other IF:
        if row == destR and col == destC:  # no parentheses needed
            return path
        # reorder conditions in next IF statement
        if (row,col) in visited or row < 0 or row > len(map)-1 or col < 0 or col > len(map[0])-1 or map[row][col] != 'road':
            return None
        visited.append((row,col))
        others=[]
        others.append(self.path_helper(visited,path[:],row-1,col,destR,destC))
        others.append(self.path_helper(visited,path[:],row+1,col,destR,destC))
        others.append(self.path_helper(visited,path[:],row,col-1,destR,destC))
        others.append(self.path_helper(visited,path[:],row,col+1,destR,destC))
        others = list(filter(None, others))  # delete ALL occurrences of None
        return self.getMin(others)

还有其他一些可以改进的地方(比如对 visited 使用 set,而不是用你自己的变量隐藏原生 map 函数),但是上面提到的更改将使它起作用。