![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() ![]()
Backtracking ist ein Verfahren nach dem Trial-and-Error-Verfahren (Versuch und Irrtum) arbeitet. Mit Backtracking versucht man aus Teillösungen systematisch zu einer Komplettlösung zu kommen. Wenn man zum Beispiel aus einer der Teillösung nicht mehr weiterkommt ein Problem zu lösen wird ein oder mehrere Schritte rückgängig gemacht. Die reduzierte Teillösung versucht man dann auf einen anderen Weg wieder aufzubauen. Falls auf diesem Weg wieder eine Sackgasse auftretet gehen wir wieder ein oder mehrer Schritte zurück. So lange bis wir eben zu einer Lösung des Problems kommen oder auch feststellen müssen das es zu diesem Problem keine Lösung gibt.
Wir wollen hier das 'C' (Pacman)zum Zeichen 'o' (Essen) bringen. Die '*'-Zeichen sollen Hindernisse für unseren Pacman darstellen. Das ganze Spielfeld wollen wir auf einem zweidimensionalen char - Array darstellen...
...also 15 Zeilen und 50 Spalten. Wir wollen unseren Pacman vorerst in 4 Richtungen bewegen lassen können....
![]()
Also benötigen wir 4 Funktionsselbstaufrufe. Für jede Richtung eine. Eine für Richtung x+ (1 Zeile runter), x- (1 Zeile hoch), y+ (Eine Spalte nach Rechts), y- (Eine Spalte nach Links). Die 4 Funktionsselbstaufrufe sehen deshalb in etwa so aus....
Damit hätten wir für jede Richtung einen Funktionsselbstaufruf. Jetzt übergeben wir noch, nur für die Grafische Darstellung, an die Funktion die alten Positionen von x und y....
xalt und yalt dienen nur der Grafischen Darstellung. Mit Backtracking hat das aber jetzt nichts zu tun. Nun müssen wir festlegen in welche Richtung und wohin unser Pacman als erstes gehen soll. Da unser Pacman an der Position [1][1] ist und unser Essen an der Position [13][48] können wir uns überlegen ob wir als erstes in Richtung y+1 (1 Spalte nach rechts) oder x+1 (1 Zeile nach unten) gehen. Ich habe mich zuerst für die Richtung y+1 (1 Spalte nach rechts) entschieden. Bevor wir aber zuerst in die Richtung y+1 gehen müssen wir überprüfen ob in dieser Richtung ein Hindernis (*) ist oder ob wir das Ende des Spielfeldes bereits erreicht haben. Zusätzlich müssen wir noch überprüfen ob unsere alte Spalte (yalt) nicht schon einen Funktionsaufruf zuvor besucht wurde (yalt!=y+1) . Zusätzlich wird, wenn alle Bedienungen erfüllt sind die Funktion erneut aufgerufen 'step(x,y+1,x,y)'. Entscheidend ist nun ob der erneute Funktionsaufruf als Rückgabewert 1 (return 1) oder 0 (return 0) liefert. Wird 1 zurückgegeben wird der Zug ausgeführt. Aber das bringt Ihnen jetzt gar nichts bevor sie die fertige Funktion nicht kennen. Hier jetzt der 1. Funktionsaufruf.....
Die nächsten drei if-else-Anweisung sehen ähnlich aus mit dem einzigen Unterschied das jede für eine andere Richtung bestimmt ist. Hier nun die die nächsten 3 Anweisungen für die Richtung 'x+,x- und y-' ....
Falls keine dieser 4 Aufrufe Erfolgreich war wird an die vorangegangene Funktion der Wert 0 (return 0) zurückgegeben und das heißt das dieser vorangegangen Funktionsaufruf (Zug) nicht ausgeführt wird. Die Abbruchbedienung haben wir wenn unser Pacman 'C' auf der selben Position ist wie 'o' auf dem Spielfeld. "Abgebrochen" wird aber auch wenn das Labyrinth zu komplex ist und unser Pacman Paartour nicht ans Ziel finden will oder er in einer Sackgasse festhängt wo es kein zurück mehr gibt. Leider bedeutet dieser Abbruch einen Stacküberlauf. Hier die komplette Funktion.....
Wollen wir zum Test kurz ein paar Durchläufe machen. Zuerst übergeben wir an die Funktion...
Somit gäbe sich in etwa folgendes Beispiel....
Als erstes wird überprüft ob wir am Ziel sind....
danach wird überprüft ob die Position [x][y] frei sind...
Wenn ja wir unser Pacman 'C' dort hingesetzt und es sieht aus wie in der linken Abbildung oben. Jetzt wird überprüft in welche Richtung Pacman gehen kann....
Ja die Richtung y+1 ist frei und wurde auch nicht zuvor besucht. Somit liegt auf dem Stack jetzt folgendes....
Dieser Wert wartet jetzt um Ausgeführt zu werden auf den Rückgabewert 1. Schon geht es zum nächsten Funktionsaufruf. Folgende Schritte haben wir bisher gemacht (von unten nach oben)....
Nun sieht das bildlich folgendermaßen aus....
Nun kann man erkennen das Pacman ein Hindernis ('*') vor sich hat. Also wir die erste if - Anweisung dieses mal nicht zum Zuge kommen. Wie sieht es mit der 2. aus?
Können wir eine Zeile tiefer gehen (x+1)? Ja wir können somit wird nun...
...aufgerufen. Somit sieht's mit Pacman folgendermaßen aus.....
Somit wäre Pacman momentan an Position [2][3]. Sie können das ganze ja mal ein paar Schritte Weiterdurchgehen. Ich habe Ihnen dazu jetzt auch ein Programm geschrieben womit sie das ganze Beispiel am Bildschirm demonstriert bekommen....
Nun der Code ist stark auf einem Rechtdrang ausgerichtet, wenn sie Pacman in eine andere Richtung schicken wollen müssen sie das Backtracking Ihren Bedürfnissen anpassen. Erhöhen sie mal die Anzahl der HINDERNISSE und sie werden merken das unser Pacman irgendwann auch keinen Ausweg mehr findet obwohl es eigentlich einen gäbe. Das heißt Pacman dreht sich im Kreis. Nun haben wir als eine Möglichkeit den Code noch mehr zu verkomplizieren oder wir machen Pacman noch eine Spur "Intelligenter" und lassen in auch noch in allen Richtungen diagonal laufen. Somit kann sich Pacman in 8 Richtungen fortbewegen....
![]()
Somit hätten wir folgende 4 neue Koordinaten....
Jetzt müssen wir erneut die Reihenfolge zusammensetzten damit wir auf den schnellsten Weg ins Ziel kommen. Unser Ziel ist rechts unten somit sollten wir diese Richtung als Priorität benutzen. Ich schlage folgenden Weg vor....
Wenn jemand einen besseren Vorschlag dazu hat würde mich freuen. Nun wollen wir das ganze in unsere Funktion einbauen.....
Mit 8 Wegen schafft unser Pacman nun schon mehrere Hindernisse auf einmal. Aber ab einer gewissen Anzahl von Hindernisse happerts auch hier wieder obwohl wir noch nicht in eine Sackgasse gekommen sind. Also benötigen wir noch eine Funktion die sich merkt ob wir ein Feld bereits besucht haben oder nicht. Dies stellt sich als einfaches Unterfangen da. Wir benutzen ein weiteres zweidimensionales Array.....
Alle Felder initialisieren wir mit dem Wert 0. Jetzt müssen wir nur noch in unserem Programm nur noch die Position die wir bereits besucht haben den Wert 1 übergeben. Jetzt können wir in unseren if-else-Anweisungen noch die Abrage einbauen...
Sie können das Verbesserte Programm hier herunterladen ....
![]() baktrak2.c
Danke muss ich auch an Wolfgang von www.pro-linux.de sagen der mir mit 2-3 Sätzen das Prinzip von Backtracking erklärt hat....
![]() ![]() ![]() |