J'ai codé mon premier algorithme légèrement complexe, une implémentation de l'algorithme n tracé d'étoile . J'ai suivi certains conseils Python.org sur la mise en œuvre de graphiques afin qu'un dictionnaire contienne tous les nœuds que chaque nœud est également lié. Maintenant, comme tout cela est pour une partie, chaque nœud n'est vraiment qu'un tuile dans une grille de nœuds, comment je travaille sur la heuristique et la référence occasionnelle.
Merci au TimeIt, je sais que je peux exécuter cette fonction avec succès un peu plus de cent fois par seconde. Naturellement, cela me rend un peu inquiet, c'est sans aucune autre "affaire de jeu", comme des graphiques ou du calcul de la logique de jeu. J'adorerais donc voir si l'un d'entre vous peut accélérer mon algorithme, je suis complètement inconnu avec Cython ou Kin, je ne peux pas coder une ligne de C.
Sans plus de randonnée, voici ma fonction d'étoile.
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
Une optimisation facile consiste à utiliser des ensembles au lieu de listes pour les ensembles ouverts et fermés.
openSet = set()
closedSet = set()
Cela fera tout le tout le in
et not in
tests O(1) au lieu de O (n).
J'utiliserais les ensembles comme on l'a dit, mais j'utiliserais également un tas pour trouver l'élément minimum (celui qui sera le suivant current
). Cela nécessiterait de garder à la fois un Openset et un OpenHeap, mais la mémoire ne devrait pas vraiment être un problème. En outre, définit Insert In O(1) et des tas dans O (journal n) afin qu'ils soient rapides. Le seul problème est que le module HePQ n'est pas vraiment fait pour utiliser des clés avec elle . Personnellement, je voudrais simplement le modifier pour utiliser des clés. Cela ne devrait pas être très difficile. Alternativement, vous pouvez simplement utiliser des tules de (tuile.h, tuile) dans le tas.
En outre, je suivrais l'idée d'Aaronasterling d'utiliser l'itération au lieu de récursivité, mais aussi, je voudrais ajouter des éléments à la fin de path
et inverse path
à la fin. La raison en est que l'insertion d'un élément à la 0ème place dans une liste est très lente (O (n) je crois), tandis qu'appounfin est O(1) Si je me souviens bien. La finale Le code de cette partie serait:
def retracePath(c):
path = [c]
while c.parent is not None:
c = c.parent
path.append(c)
path.reverse()
return path
Je mettais le chemin de retour à la fin parce qu'il est apparu qu'il devrait de votre code.
Voici le code final en utilisant des ensembles, des tas et de la non:
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 []
Comme suggéré ci-dessus, faites closedSet
dans un ensemble.
J'ai essayé de coder openList
comme un tas 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
Cependant, vous devez toujours rechercher sur if tile not in openList
, alors je ferais ceci:
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 []