最初の少し複雑なアルゴリズムである A Star Pathfinding アルゴリズムの実装をコーディングしました。グラフの実装について Python.orgのアドバイス に従って、各ノードがリンクされているすべてのノードを辞書に含めました。さて、これはすべてゲームに関するものなので、各ノードは実際にはノードのグリッド内の単なるタイルであり、したがって、私はどのようにヒューリスティックを計算していて、それらを時々参照しています。
Timeitのおかげで、この関数を1秒あたり100回強正常に実行できることがわかりました。当然のことながら、これは私を少し不安にさせます。これには、グラフィックスやゲームロジックの計算など、他の「ゲームに関すること」が行われていないためです。だから、私のアルゴリズムをスピードアップできる人がいるかどうかを確認したいのですが、私はCythonに完全に慣れていないか、それとも親切です。Cの行をコーディングすることはできません。
これ以上とりとめなく、これが私のスター関数です。
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
簡単な最適化は、オープンセットとクローズセットのリストの代わりにセットを使用することです。
openSet = set()
closedSet = set()
これにより、O(の代わりにin
およびnot in
テストがすべてO(1)になります)ん)。
前述のようにセットを使用しますが、ヒープを使用して最小要素(次の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 []
上記のように、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 []