A* algorythmus - Speed vs Speicher - wie vorgehen? :)
Übersicht
BlitzMax, BlitzMax NG
Beginners-Corner
PhillipKBetreff: A* algorythmus - Speed vs Speicher - wie vorgehen? :) |
Antworten mit Zitat |
|
|---|---|---|
|
Nachtrag:
Ich liste hier mal meine Fragen auf, da die im Text untergegangen sind glaube ich *g* (und noch ein wenig erweitert!) (1) Wäre jemand so freundlich mein TAStern2d - objekt durchzuschauen? Ich weiß nicht recht, ob ich das speichern der Offenen und geschlossenen einträge so lassen kann. Wenn 20 Wegfindungen vorhanden sind, und immer nur die erste bearbeitet wird, könnte es sau lange dauern. Alle gleichzeitig abzuarbeiten würde aber den RAM sprengen. Ich bin mir ein wenig unsicher ^^ (2) Läuft die Wegfindung bei euch flüssig, wenn ihr beide Quellcodes in ein Programm werft und per Linksklick die Unit rumschickt? (3) Ist der Algorythmus richtig umgesetzt? Ist das wirklich A* ? (4) Gibt es eine bessere Methode, die "Offenen" einträge zu speichern, als in einer TList? Geschwindigkeit und Ramverbrauch sind seeeehr wichtig für mein vorhaben! (5) Sind die abfragen soweit richtig sortiert, oder wäre es Chronologisch sinnvoller, die abbruchsbedingungen im AStern - Knotencheck (prüfung, ob ein Knoten bereits irgendwo bearbeitet wurde!) anders zu sortieren? Wieder: Performance ist sehr wichtig! (6) Kann ich eventuell etwas Ressourcenarmeres nutzen, um die TKnoten zu sortieren? Vielleicht sogar einzelwerte? Ich sehe ein TKnoten leider als beste methode momentan, aber die zwingt mich zur TList (und die ist beim Iterieren ja nicht grade die schnellste :<) Vielleicht doch lieber eine Art array mit festgelegter Größe? Hoffentlich gibts antworten *g* ------------------- Heyho! Ich habe mich die letzten 2 Tage mit einem A* algorythmus beschäftigt, der als erste grundlage für eine wegfindung in meinem Projekt dienlich sein soll. Der Algorythmus an sich hat super funktioniert, war allerdings recht schlampig durchgearbeitet, da ich zuerst keinen wirklichen anhaltspunkt hatte, wie ich die informationen genau brauche. Nun schreibe ich das ganze grade in ein Type um, worin jede instanz dieses Objektes eine eigene Wegfindung durchführt und sich in einer Globalen liste registriert, um dort über eine Updatemethode auf mehrere Frames verteilt ihre berechnungen durchführt. A* sieht (laut tutorial^^) ja so aus: 2 Listen - Offen und geschlossen Jeder eintrag ist ein "Knoten", welcher 3 werte hält: Schrittkosten, Geschätze entfernung zum Ziel, Wegkosten gesamt. In meinem Tutorial waren die werte mit f g und h bezeichnet. F = Kosten gesamt H = heuristic? Entfernung zum Ziel (geschätzt!) G = Schrittkosten (10 für Vertikal/Horizontal, 14 für diagonalen schritt) Der Tutorial ersteller hatte diese Knoten in einer "Liste" sortiert. Ich nahm also zuerst an, er meinte eine Linked List. Allerdings meinte er auch, das er die "Offen" (dh noch zu prüfende, angrenzende wegpunkte) nach ihren F kosten sortiert. Das klang wiederrum nach einem Array. Meine erste version sah nun auch so aus, das ich einen Array immer um 1 Element erweitert hatte, später wollte ich dann auf eine "Finde freien Platz"-methode umsteigen und zb einen TKnoten[] mit Länge 100 halten, sollte dieser nun mehr einträge benötigen, um weitere 100 erweitern. Das lief aber ganz und garnicht und ich bin Frustriert auf TList umgestiegen. Danach lief der Algo auch super - ein paar kleinere abfragen musste ich zwar noch fixen, aber ansonsten liefs. Nachdem es liefs, stieß ich allerdings auf mehrere Probleme: 1) Wegfindung die Komplex war, produzierte aufgrund einer Rekursiven Funktion ab und zu einen Absturz 2) Der Speicherbedarf war enorm - bei Komplexen Findungen hatte ich gute 50mb Speicher belegt (konnte aber aufgrund der Rekursion sein, ich weiß ehrlich gesagt nicht, wann der GCC so ausgeführt wird^^) 3) Es war absolut nichts zu rütteln, komplexe wegfindungen haben 2-3 Sekunden gebraucht. -------------------------- Schritt 2: umschreiben in einen Type Gut, aufgrund der Rekursion wollte ich stattdessen Iterativ (nennt sich das so?^^) das ganze abarbeiten. Dazu noch einen Wert, wieviele Knoten pro durchlauf getestet werden sollte. Dh nicht so wichtige wegfindungen liefen mit 30knoten pro Frame, wichtigere konnten dann mal 200 machen. Es ist ja nur menschlich, wenn jemand mal grade überlegt, wo er langlaufen muss Als "Offen" halte ich nun eine TList und als "Geschlossen" einen Simplen Byte[,], welcher die Mappositionen wiederspiegelt und TRUE/FALSE werte enthält. False = Punkt ist nicht als Geschlossen makiert, true = Er ist als geschlossen makiert. (anmerkung: Die Geschlossenen Punkte enthalten bereits den Absolut besten weg zu diesem Punkt - die Offenen müssen noch überprüft werden) Ich werde noch grade ein wenig an dem Type feilen müssen, der läuft grade nicht richtig. Wenn ers dann tut, werde ich mal meinen Code hier rein stellen und auf rückmeldung hoffen Ist das der richtige ansatz - eine Instanz erstellen und in einzelschritten abarbeiten -> Fördert FPS. Dazu die Linked List aufgrund ihrer Dynamic. Für die geschlossene liste brauche ich keine Pointer halten, da diese irgendwo in den Verlinkungen der Knoten noch existiert - nur die "offenen" sind relevant. Gibt es eventuell eine methode, mit der ich einen TKnoten[] nach einem TKnoten.field sortieren kann? Um genauer zu sein, nach .f ? =) Dafür auchnoch einen Algorythmus bauen wäre mir zu schwer. Sollte ich vielleicht - aufgrund der geschwindigkeit - keine TKnoten-instanzen verwenden, sondern die werte anders sortieren? Wenn ja, wie? Ps: Ich brauch hoffentlich nicht lange, um meinen Type umzuschreiben - die Test Szene ist zwar hoffnungslos schlecht gecoded, aber es reicht evtl, das ihr mich mit Kritik am Type AStern2d in der luft zerreißen könnt und mir dann doch ein bissl helfen könnt *g* Edit: So, diverse kleinere Fehler behoben. Die Type version wählt zwar noch nicht den besten weg, aber es ist ziemlich schnell. Speicherverbrauch habe ich noch nicht überprüft - hoffentlich nicht zu viel Meine Testversion beinhaltet folgendes: Einstellbares raster (über CONST rSizeX und rSizeY vor programmstart!), eine TUnit einheit, die per Mausklick platziert werden kann und über einenen weiteren Mausklick (links!) mit dem Type-system rumgeschickt wird. Mittlere Maustaste-klick nimmt die alte methode (Rekursiv! Aufpassen, kann leicht die maximale Rekursions-tiefe eures Prozessors erreichen ->Programmabsturz). Per Rechtsklick lassen sich wände in die Map eintragen - diese werden bei der Wegfindung natürlich nicht genutzt. Die Unit sucht automatisch einen neuen weg, falls ihr nächster Knotenpunkt mittlerweile eine wand ist. Das ganze ist nicht wirklich sauber, aber es ist ja auch nur ein erster Test - und die Wegfindung steht mir im vordergrund! Sollte kein weg gefunden werden, bricht der Algorythmus ab und löscht sich selbst. Hier mal ein Screenshot: Der kleine rote punkt ist meine "TUnit" Dieser dauerte 1-2sekunden und ist ziemlich komplex. Eine Diagonale bewegung an der wand lang wird nicht akzeptiert (ganz gut an den harten kanten sichtbar!) Und hier mein Testcode. Hauptprogramm: BlitzMax: [AUSKLAPPEN] SuperStrict (ich weiß, viel ist auskommentiert - vieles sind zb Debugprints oder debugprints!) Type TAStern2d: BlitzMax: [AUSKLAPPEN]
Ausserdem ist beim Type auch eine Debug-print methode drinne. Diese braucht allerdings 3 listen, deren füllung im AStern algo deaktiviert ist. |
||
|
|
mpmxyz |
Antworten mit Zitat |
|---|---|---|
|
Ich habe mich mal um (1), (3), (4) und (6) gekümmert. Ja, der Algorithmus scheint A* zu sein, aber es gibt eine große Perforancebremse: die offene Liste. Es ist wichtig, dass dort bekannt ist, welcher Eintrag der "beste" ist. Dazu kann man entweder suchen oder sortieren. Das Problem: Bei verketteten Listen als auch bei Arrays braucht das bei doppelt so viel Einträgen auch jeweils doppelt so viel Zeit. (bei 3facher Anzahl die 3fache Zeit usw., bei Wikipedia auch im Abschnitt "naive Implementierung" zu finden Es gibt aber noch eine wichtige dritte Möglichkeit: Bäume. (In BlitzMax werden sie in "TMap" verwendet.) In ihnen werden die Einträge automatisch schnell und richtig sortiert. Hier gibt es eine Implementierung für eine solche Prioritätswarteschlange: https://www.blitzforum.de/foru...p?p=313906 Die für dich wichtigen Operationen sind: add, isEmpty und removeHighest mfG mpmxyz |
||
|
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer |
||
PhillipK |
Antworten mit Zitat |
|
|---|---|---|
|
TMap *grübel*
Klar, ich weiß was das ist. Aber, jetzt ohne HamZta's beitrag (dein Link Vielleicht ergibt sich mir ja mehr, sobald ich diesen durchgelesen hab. Die einzige idee die ich hatte, den "besten" eintrag zu kennen, würde am ende sogar langsamer sein und noch dazu den Ram sprengen. Bin mal lesen und editier dann hier mal rein *g* Edit: Hmpf, es erschließt sich mir immernoch nicht ganz. Das problem ist, das die Priorität variabel ist. Ich habe keine ahnung, wie HamZta's funktion läuft, das geht über meinen verstand hinaus Ausserdem brauche ich auch zugriff auf die Punkte an einer gewissne position - eine möglichkeit, alle einträge in HamZta's objekt durchzugehen, sehe ich so auf die schnelle nicht. Muss mich da wohl erstmal reinlesen :< Vielleicht kann ich ja ein paar methoden Adden, zb um eine Priorität zu ändern. Wenn ich das richtig verstanden habe, könnte ich mir die THeapNodes speichern und nach dem ändern der Priorität _heapify() aufrufen. |
||
PhillipK |
Antworten mit Zitat |
|
|---|---|---|
|
Mist.
Ich habe mir eine Methode gebastelt, die ein Obj in der Data - liste sucht und seine priorität ändert. Allerdings klappt es so auch nicht wirklich. Wo genau das problem liegt, weiß ich nicht. Es ist nur unheimlich langsam, je komplexer die wegfindung wird - grund hierfür ist eine falsche abfrage, welche ich noch finden muss. Eben hatte eine liste, die jeden "offen" eintrag hält, über 6000 einträge. Meine map mit 75x75 tiles hat aber nur was bei 5600 felder Ich benötige noch ein paar mehr ideen und wissen über die funktion dieses Type's von HamZta, aber damit dürfte es in der Tat schneller werden. Leider ist die Priorität ziemlich statisch darin verankert, deswegen werde ich da auch nichts neu schreiben können. Hoffentlich ist das neusortieren eines Node's nicht zu langsam - aber rein vom code her, dürfte das nicht sein |
||
|
|
XeresModerator |
Antworten mit Zitat |
|---|---|---|
|
PhillipK: Auch du bist dazu angehalten, keine Doppelposts zu produzieren und wenn nötig stattdessen deine Beiträge zu editieren.
Haben Sie vielen Dank für Ihr Verständnis! |
||
|
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus THERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld) |
||
PhillipK |
Antworten mit Zitat |
|
|---|---|---|
|
Entschuldige, da war ich wohl blöd. Das mach ich manchmal zwar absichtlich, allerdings diesmal nicht.
Wie wärs mit einer Merge-funktion für 2 hintereinanderliegende Beiträge vom selben poster? *g* Wenn mans bemerkt, vermerkt man, das man seinen beitrag mit dem vorherigen zusammenfügen möchte und zack, inhalt aus 2) wird in inhalt von 1) eingefügt, 2) wird gelöscht. *hust* Mittlerweile habe ich mein Problem gefunden. Er findet nun wieder wege, aber entgegen der erwartungen: Langsamer als mit den TList. Das liegt vllt am stetigen neusortieren des Arrays - da ich gute 5 Knoten pro durchlauf adde, dürfte das einfach zu viel sein. Wenn ich durch das System durchgestiegen bin, passe ich es eventuell auf meinen A* algorythmus an - mehrere Arrays für verschiedene Prioritätstiefen. dann müssen nur ein wertebereich neu sortiert werden. Mit einem Array of Arrays sollte das kein akt sein |
||
Übersicht
BlitzMax, BlitzMax NG
Beginners-Corner
Powered by phpBB © 2001 - 2006, phpBB Group
