Ich habe dies gelesen: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html
Aber es gibt einige Dinge, die ich nicht verstehe, zum Beispiel, in dem Artikel heißt es, dass man so etwas für die Wegfindung mit diagonalen Bewegungen verwenden soll:
function heuristic(node) =
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * max(dx, dy)
Ich weiß nicht, wie man D setzt, um einen natürlich aussehenden Pfad wie in dem Artikel zu erhalten, ich setze D auf die niedrigsten Kosten zwischen benachbarten Quadraten, wie es heißt, und ich weiß nicht, was sie mit dem Zeug über die Heuristik gemeint haben sollen sei 4 * D, das scheint nichts zu ändern.
Dies ist meine heuristische Funktion und Bewegungsfunktion:
def heuristic(self, node, goal):
D = 5
dx = abs(node.x - goal.x)
dy = abs(node.y - goal.y)
return D * max(dx, dy)
def move_cost(self, current, node):
cross = abs(current.x - node.x) == 1 and abs(current.y - node.y) == 1
return 7 if cross else 5
Ergebnis:
Den reibungslosen Segelweg wollen wir schaffen:
Der Rest meines Codes: http://pastebin.com/TL2cEkeX
Aktualisieren
Dies ist die beste Lösung, die ich bisher gefunden habe:
def heuristic(node, start, goal):
dx1 = node.x - goal.x
dy1 = node.y - goal.y
dx2 = start.x - goal.x
dy2 = start.y - goal.y
cross = abs(dx1*dy2 - dx2*dy1)
dx3 = abs(dx1)
dy3 = abs(dy1)
return 5 + (cross*0.01) * (dx3+dy3) + (sqrt(2)-2) * min(dx3, dy3)
def move_cost(current, node):
cross = abs(current.x - node.x) == 1 and abs(current.y - node.y) == 1
return 7 if cross else 5
Ab dem zweiten Bild wird der gewünschte Pfad erstellt, Hindernisse werden jedoch nicht gut bewältigt (es kann an Wänden kriechen), und manchmal werden auf längeren Strecken keine optimalen Pfade erstellt.
Welche Verbesserungen und Optimierungen kann ich anwenden, um es zu verbessern?
quelle
Antworten:
Ein * gibt den kürzesten Weg in der Grafik an. Wenn Sie ein Raster als Diagramm verwenden, gibt es häufig mehrere kürzeste Pfade. In Ihrem ersten Diagramm ist dies einer der kürzesten Wege. Dabei werden zuerst alle Axialbewegungen und danach alle Diagonalbewegungen ausgeführt. Aber das ist der gleiche Längenpfad, als würden Sie alle Diagonalen zuerst setzen oder axiale und diagonale Bewegungen mischen. Diese sind alle äquivalent kurz und welche A * -Auswahl davon abhängt, wie der Code geschrieben und wie das Diagramm dargestellt wird.
Ich denke, was Sie wollen, ist entweder:
quelle
Mit dem A * -Algorithmus können Sie Pfadkanten unterschiedliche Kosten zuweisen. Sie können je nach Umständen auch Kosten zuweisen. Dies ist Ihr Hauptwerkzeug, um A * -Pfade so zu formen, dass sie so aussehen, wie Sie es möchten.
Wenn Sie lange Diagonalen abschrecken möchten, können Sie sie bestrafen. Fügen Sie ein kleines bisschen Kosten für jedes Mal hinzu, wenn der Pfad in die gleiche Richtung verläuft. Wenn Sie dies tun, versucht der Algorithmus automatisch, diagonale Schritte so gleichmäßig wie möglich über den gesamten Pfad zu verteilen. Stellen Sie nur sicher, dass diese zusätzlichen Kosten niemals höher sind als die Kosten für einen zusätzlichen Vorteil. Andernfalls führt der Algorithmus zu völlig unnötigen Umwegen, um gerade Linien zu vermeiden.
Eine gute Formel könnte sein:
cost = normal_cost * (1.1 - 0.1 / num_of_steps_in_the_same_direction
)Beachten Sie, dass hierfür die Pfadkosten als Gleitkommawerte und nicht als ganze Zahlen nachverfolgt werden müssen.
quelle
Anpassung von A *
Wie Philipp sagte, sollten Sie Kosten hinzufügen, wenn sich die Richtung für lange Zeit nicht ändert. Die Funktion von Philipp kann jedoch schnell dazu führen, dass zusätzliche Kosten summiert werden, die höher sind als die Kosten für das Durchqueren einer zusätzlichen Kachel. Aber seine Schlüsselidee ist richtig!
Es scheint einfach zu sein, A * anzupassen, um "alle" optimalen Pfade (mit kürzester Länge) zu berechnen und dann einen von ihnen durch eine andere Heuristik auszuwählen. Aber es gibt ein Problem. Wenn Sie einen langen Weg haben, gibt es möglicherweise viele Lösungen mit optimaler Länge. Dies führt dazu, dass der A * -Algorithmus viel länger benötigt, um alle diese anderen Lösungen zu berechnen. Das liegt am Gitter. Sie können nicht um 80 Grad anstatt um 90 Grad gehen, was zu mehreren suboptimalen Lösungen anstelle einer optimalen Lösung führt. Stellen Sie sich als Vorstellungskraft eine Karte ohne Hindernisse vor. Die x-Distanz ist 2, die y-Distanz ist 3. Dies bedeutet, dass alle kürzesten Pfade 2 diagonale Bewegungen und 1 gerade Bewegung haben. Für diesen einfachen Pfad gibt es 3 gültige Kombinationen: SDD, DSD, DDS (wobei D = Diagonale, S = Gerade). Der echte "Spaß" fängt schon an, wenn man Wege mit zB hat 3 gerade und 2 diagonale Bewegungen: SSSDD, SSDSD, SSDDS, SDSSD, SDSDS, SDDSS, DSSSD, DSSDS, DSDSS, DDSSS (10 Variationen des kürzesten Pfades, wenn ich keinen verpasst habe). Ich denke, du hättest auf die Idee kommen sollen ...
Wir sollten dies beheben, indem wir die Kostenfunktion so anpassen, dass weniger Lösungen (oder sogar nur eine Lösung) "optimal" sind.
Kostenfunktion anpassen
Wenn Sie die Anpassung durchführen, wie Philipp in seiner Beispielformel vorschlägt, erhalten Sie viel bessere Ergebnisse, es treten jedoch noch einige Probleme auf. Die kürzeren / längeren "Teile" werden nicht gleichmäßig auf dem Pfad verteilt, was bedeutet, dass die Richtungsänderungen häufiger am Anfang des Pfades erfolgen oder umgekehrt.
Außerdem scheint ein Weg, auf dem der Schauspieler endlos "drehen" muss, suboptimal zu sein, wenn er von einem Menschen beobachtet wird. Da es Zeit braucht (um die Turn-Animation zu zeigen), muss es langsamer sein.
Anstatt Floats für die Kosten zu verwenden, können Sie jedoch ein "sekundäres Kosten-" oder ein sekundäres Sortierkriterium implementieren. Wenn die Primärkosten gleich sind, werden die Sekundärkosten verwendet, um abzuschätzen, welche Lösung vorzuziehen ist. Dies führt nicht versehentlich zu einer Erhöhung der Primärkosten (Streckenlänge im Rastermaß).
quelle