我编写了第一个稍微复杂的算法,即A Star Pathfinding算法的实现。我在实现图表时遵循了一些Python.org advice,因此字典包含每个节点都链接的所有节点。现在,由于这只是游戏的一部分,每个节点实际上只是节点网格中的一个区块,因此我如何计算启发式和偶尔引用它们。
感谢timeit我知道我可以成功运行这个功能一秒钟一百多次。可以理解这让我有点不安,这是没有任何其他'游戏的东西'继续下去,如图形或计算游戏逻辑。所以我很想知道你们中是否有人可以加速我的算法,我完全不熟悉Cython或它的亲属,我不能编写一行C语言。
没有更多的漫步,这是我的A Star功能。
def aStar(self, graph, current, end):
openList = []
closedList = []
path = []
def retracePath(c):
path.insert(0,c)
if c.parent == None:
return
retracePath(c.parent)
openList.append(current)
while len(openList) is not 0:
current = min(openList, key=lambda inst:inst.H)
if current == end:
return retracePath(current)
openList.remove(current)
closedList.append(current)
for tile in graph[current]:
if tile not in closedList:
tile.H = (abs(end.x-tile.x)+abs(end.y-tile.y))*10
if tile not in openList:
openList.append(tile)
tile.parent = current
return path
答案 0 :(得分:38)
一个简单的优化是使用集合而不是列表来打开和关闭集合。
openSet = set()
closedSet = set()
这将使所有in
和not in
测试O(1)而不是O( n )。
答案 1 :(得分:9)
我会使用已经说过的集合,但我也会使用堆来查找最小元素(将是下一个current
的元素)。这将需要保持openSet和openHeap,但内存不应该是一个问题。另外,在O(1)中设置插入,在O(log N)中设置插值,这样它们就会很快。唯一的问题是heapq模块并没有真正使用密钥。就个人而言,我只是修改它来使用密钥。这应该不是很难。或者,您可以在堆中使用(tile.H,tile)元组。
另外,我会遵循aaronasterling的使用迭代而不是递归的想法,但是,我会在最后添加元素到path
的末尾并反转path
。原因是在列表中的第0位插入一个项目非常慢,(我相信是O(N)),而如果我没记错的话,附加是O(1)。该部分的最终代码为:
def retracePath(c):
path = [c]
while c.parent is not None:
c = c.parent
path.append(c)
path.reverse()
return path
我把返回路径放在最后,因为它似乎应该来自你的代码。
这是使用集合,堆和最后代码的最终代码:
import heapq
def aStar(graph, current, end):
openSet = set()
openHeap = []
closedSet = set()
def retracePath(c):
path = [c]
while c.parent is not None:
c = c.parent
path.append(c)
path.reverse()
return path
openSet.add(current)
openHeap.append((0, current))
while openSet:
current = heapq.heappop(openHeap)[1]
if current == end:
return retracePath(current)
openSet.remove(current)
closedSet.add(current)
for tile in graph[current]:
if tile not in closedSet:
tile.H = (abs(end.x - tile.x)+abs(end.y-tile.y))*10
if tile not in openSet:
openSet.add(tile)
heapq.heappush(openHeap, (tile.H, tile))
tile.parent = current
return []
答案 2 :(得分:5)
如上所述,将closedSet
设为一个集合。
我尝试将openList
编码为堆import heapq
:
import heapq
def aStar(self, graph, current, end):
closedList = set()
path = []
def retracePath(c):
path.insert(0,c)
if c.parent == None:
return
retracePath(c.parent)
openList = [(-1, current)]
heapq.heapify(openList)
while openList:
score, current = openList.heappop()
if current == end:
return retracePath(current)
closedList.add(current)
for tile in graph[current]:
if tile not in closedList:
tile.H = (abs(end.x-tile.x)+abs(end.y-tile.y))*10
if tile not in openList:
openList.heappush((tile.H, tile))
tile.parent = current
return path
但是,您仍然需要在if tile not in openList
进行搜索,所以我会这样做:
def aStar(self, graph, current, end):
openList = set()
closedList = set()
def retracePath(c):
def parentgen(c):
while c:
yield c
c = c.parent
result = [element for element in parentgen(c)]
result.reverse()
return result
openList.add(current)
while openList:
current = sorted(openList, key=lambda inst:inst.H)[0]
if current == end:
return retracePath(current)
openList.remove(current)
closedList.add(current)
for tile in graph[current]:
if tile not in closedList:
tile.H = (abs(end.x-tile.x)+abs(end.y-tile.y))*10
openList.add(tile)
tile.parent = current
return []