Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

11

04.08.2013, 16:51

In Listen kann man nur sehr schwer sortieren, weil es keinen Random Access gibt. Damit kann man dann viele Algorithmen nicht mehr effizient durchfuehren. Ich wuerde das erstmal ignorieren, solange es ehh nicht funktioniert ist die Performance ja egal...

Wenn du uebrigens nur noch in 4 Richgtungen gehen kannst, dann solltest du wieder deine urspruengliche Schaetzfunktion benutzen.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

12

04.08.2013, 19:26

Versuch es mal mit float und der Norm sqrt(x*x + y*y).

Aber das ist falsch, wenn er in einem Schritt diagonal gehen kann.
Dann kostet das nämlich genauso viel wie ein Schritt nach links, rechts, oben oder unten.

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

13

04.08.2013, 21:18

Gerade Schritten kosten bei ihm 10 und diagonale 14. Wenn man das Ergebnis der Wurzel also noch mit 10 multipliziert, ist es akzeptabel. In Grids ist die Wurzel aber trotzdem ziemlich sinnlos. Man kann einfach die minimale Anzahl gerader und (wenn erlaubt) diagonaler Schritte bestimmen und hat so den genauen Weg ohne Hindernisse.

Nachteile der Wurzel
a) langsam, float-sqrt braucht im Vergleich zu ein paar Integer Additionen ewig
b) ungenauer, weil man diese Verbindung im Grid ja niemals nehmen kann, wenn die Punkte nicht zufaellig in der gleichen Spalte/Zeile liegen
c) instabil, weil floats dabei sind kann theoretisch jede CPU was Anderes ausrechnen, grad weil bei Grafikanwendungen ja oft die Single Precision angemacht wird

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

14

04.08.2013, 23:10

Ich weiß gerade nicht ob wir aneinander vorbeireden, aber sqrt(x*x+y*y) sollte man als Schätzer für die Kosten nutzen. Also quasi Luftlinie. Was daran falsch sein soll, verstehe ich gerade nicht. Dass sqrt nicht schnell ist, sollte allen klar sein. Aktuell gehts aber darum es erstmal zum Laufen zu bringen. Dann kann man noch wunderbar optimieren.
Besser als std::list dürfte wohl std::priority_queue sein.

@ Spiele Programmierer Warum sollte std::vector besser sein? Immerhin wird ja immer vorne ein element entfernt und ein neues element irgendwo dazwischen gepackt. Da ist ein array ja denkbar ungeeignet im Vergleich zu einer linked list, oder nicht?

@Shadow_Men std::merge braucht ein Vergleichsoperator (Leider sind die Fehlermeldungen von C++ etwas kryptisch; siehe hier "/usr/include/c++/4.7/bits/list.tcc|305|Fehler: keine Übereinstimmung für »operator<«"). Falls du da nen Tipp brauchst schreib einfach.

P.S: wenn du nicht std::priority_queue nutzen willst, dann kannst du std::list auch ohne sort nutzen. Man muss ja immer nur das Element was gerade hinzukommt an die richtige Stelle einfügen bzw. bei einer Neubewertung aus dem alten Platz löschen.

P.P.S: funktionierender Ausschnitt für ein A* auf einem Hexfeld mit open als std::list. Hier wird das sort vermieden durch entsprechendes Einfügen wie oben erwähnt.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
            //regular a-star
            while(!open.empty())
            {
                opened current = open.front();
                open.pop_front();

                size_t c_index = this->getindex(current.x,current.y);
                float current_height = heights[c_index];

                //expandNode(current)
                for(int counter = 0; counter < 6; counter++)
                {
                    int n_x         = current.x + (current.y%2 ? neighbours_odd : neighbours_even)[counter][0];
                    int n_y         = current.y + (current.y%2 ? neighbours_odd : neighbours_even)[counter][1];
                    
                    if(0 <= n_x && n_x < grid_width && 0 <= n_y && n_y < grid_height)
                    {
                        size_t n_index  = getindex(n_x,n_y);

                        if(!closed[n_index])
                        {
                            float h_diff = heights[n_index] - current_height;
                            Val tentative_g = static_cast<Val>(values[c_index] + sqrt(1+h_diff*h_diff));//cost to every closest neighbor is 1 in a hex-grid

                            if(this->infinit[n_index] || tentative_g < this->values[n_index])
                            {
                                this->infinit[n_index]  = false;
                                this->values[n_index]   = tentative_g;
                                opened val(n_x,n_y,tentative_g+get_approx_cost(n_x,n_y,n_index,x,y,startindex));

                                bool inserted = false;
                                typename std::list<opened>::iterator it = open.begin();
                                while(it != open.end())
                                {
                                    if(it->x == n_x && it->y == n_y)
                                        it = open.erase(it);
                                    else
                                    {
                                        if(!inserted && val.approx_cost < it->approx_cost)
                                        {
                                            inserted = true;
                                            it = open.insert(it, val);
                                        }
                                        ++it;
                                    }
                                }
                                if(!inserted)   open.push_back(val);
                            }
                        }
                    }
                }
                closed[c_index] = true;

                if(current.x == ret.first && current.y == ret.second)
                    break;
            }
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Nox« (04.08.2013, 23:21)


Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

15

04.08.2013, 23:37

Zitat

Warum sollte std::vector besser sein? Immerhin wird ja immer vorne ein element entfernt und ein neues element irgendwo dazwischen gepackt.

Schau dir den Link an.
Durch den großen Overhead bei der verketteten Liste, der schlechten Cache Nutzung, den vielen nötigen Allokationen und dem fehlenden wahlfreien Zugriff scheint es in der Praxis anders auszusehen.

Zitat

Also quasi Luftlinie. Was daran falsch sein soll, verstehe ich gerade nicht.

In der Spielewelt ist nur ein horizontales, vertikales und unter Umständen noch diagonales Bewegen möglich.
Als Heuristik sollte es eigentlich trotzdem funktionieren.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

16

05.08.2013, 14:16

Tatsache. Für den konkreten Anwendungsfall scheint std::vector echt schneller zu sein ( http://codepad.org/k1dv45Uw - Ergebnis "list+insert: 335941 vector+insert: 263493").

@Shadow_Men pardon wegen dieser Fehlinformation. Wenn es wirklich nur am sortieren liegt versuch doch mal folgendes (mit deiner ursprünglichen Version):

#include <algorithm>
+
this->SortNode(_openList); ersetzen durch std::sort(_openList.begin(),_openList.end());
+
bool operator<(const Node &ref) const { return F < ref.F; } in deine Node Klasse einbauen

P.S: was mir gerade auffällt - du speicherst zwar wo der kürzeste Weg herkommt aber kann es sein dass du diese Info bei der Pfadrekonstruktion garnicht nutzt? Weil es gibt ein fromX bzw fromY aber das wird nie wieder genutzt, oder? Aber wenn ich das richtig sehe gibt es ja schon vorher irgendwo anders ein problem.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Nox« (05.08.2013, 14:22)


TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

17

05.08.2013, 14:44

Ich weiß gerade nicht ob wir aneinander vorbeireden, aber sqrt(x*x+y*y) sollte man als Schätzer für die Kosten nutzen. Also quasi Luftlinie. Was daran falsch sein soll, verstehe ich gerade nicht.
Vielleicht solltest du mal lesen? Die Probleme davon habe ich in meinem letzten Post aufgelistet. Was ist daran nicht zu verstehen, dass man im Grid nicht die Luftlinie ablaufen kann?

Ausserdem stimmte die Formel auch in diesem speziellen Fall nicht, weil gerade Schritte 10 und diagonale 14 kosten und nicht sqrt(1) und sqrt(2). Deine Formel ist falsch und die urspruengliche war eigentlich korrekt, nur das sie diagonale Wege eben nicht beachtet. Daher schlage doch bitte nicht solche Aenderungen vor, das verwirrt ja nur noch zusaetzlich.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

18

05.08.2013, 15:16

@TGGC: Gut mein Vorschlag ist falsch. War halt ein Vorschlag, indem ich von etwas berichtete, was in den mir bekannten Anwendungfällen eben funktioniert. Wie wäre es denn mal, wenn du uns einfach nochmal mal ein Hinweis gibst wo der Fehler zu finden ist? Vielleicht kannst du ja dem Shadow_Men besser weiterhelfen?

@Shadow_Men Derweil habe ich mal ein wenig in deinem Code gewütet. Leider kann ich es nicht selbst testen, da ich kein SFML habe. Auch sind solche Vorschläge mit Vorsicht zu genießen, weil es durchaus sein kann, dass du dir damit den Lerneffekt wegnimmst oder es schlichtweg wieder falsch ist. Ansonsten wenn es dir nichts ausmacht, oder du gut anhand von (schlechten) Beispielen lernen kannst: http://codepad.org/70adD3bV (habe natürlich mal wieder alle Regeln der Groß/Kleinschreibung ignoriert)

P.S: falls es funktionieren sollte, könnte das Ersetzen von std::vector durch std::priority_queue eine gute Übung sein. kA ob die schneller ist; könnte aber zu sauberen Code führen.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von »Nox« (05.08.2013, 15:29)


19

06.08.2013, 09:34

@Nox Der Code an sich funktioniert leider nicht, aber ich konnte das alles noch selbst umsetzen und habe das Problem lösen können.

Wie ich feststellen musste lag das Problem am sichern des Pfades. Ich habe die ganze Zeit die closed List zurückgegeben, welches aber nicht wirklich der Pfad ist :dash:


Habe das jetzt so gemacht wie man es auch machen soll. Vom Ziel aus Schritt für Schritt dem Vorgänger knoten folgen.


Also Vielen Dank für die Hilfe :thumbsup:

Werbeanzeige