ZZZ bei Crash
Inhaltsverzeichnis
Vorwort
Da ich nun schon mehrfach gebeten wurde das ZZZ-Verhalten bei Crash zu erklären, nehme ich mir mal die Freiheit an dieser Stelle den ZZZ-Bug zu erläutern. Ich hoffe ich kriege das dabei so hin, dass es auch für Nicht-Informatiker verständlich ist! Den Original-Code von Didi gibt es zum selbst Nachvollziehen natürlich weiterhin unten im Anschluss zusammen mit der Diskussion und den Korrekturvorschlägen... --Ultimate 17:09, 11. Jul. 2014 (CEST)
Erläuterung des ZZZ-Bugs
Einleitung
Um die Erklärung verständlicher zu machen, werde ich sie an einem Beispiel machen. Dazu habe ich ein paar Bilder aufbereitet und werde das Vorgehen Schritt für Schritt erläutern. Ich werde dabei zwei Szenarien durchspielen, die beide gleich anfangen und dann aber unterschiedlich fortgeführt werden...
Der 1. Crash
Schritt 0 - Beispielkarte
Ich nehme für meine Erklärung einfach mal "Die Erste" Karte. Aus Platzgründen habe ich sie aber mal ein bisschen zurechtgestutzt... Für das Beispiel nehme ich mal ZZZ=4, da sich das Verhalten besser bei etwas größerem ZZZ erläutern lässt.
Schritt 1 - Gegen die Wand fahren
Möge das Rennen beginnen... Wir fahren nun einfach mal mit Vollgas gegen die Wand:
Schritt 2 - Der Algorithmus zählt rückwärts
In dem Moment indem keine Züge mehr möglich sind und klar ist, dass man crasht, wird die bisherige Route zurückverfolgt um den Zurücksetzpunkt zu finden. Dazu beginnt der Zähler (im Code $i) beim ZZZ (im Code $aussetzen), also in unserem Fall bei 4. Der Zähler zählt bis 0 rückwärst und schaut dabei für jeden Zug aus der Datenbank, ob das ein Crash war.
Hä was wie? - Ja, Crashs werden genauso wie Züge in der Datenbank abgelegt und unterscheiden sich nur durch einen zusätzlichen Eintrag. Wenn Didi also die Liste der Züge aus der Datenbank holt, sind dort auch die Crashs mittenmang. Aktuell sind wir aber noch nicht gecrasht, daher ist noch alles gut.
Schritt 3 - Crashpunkt gefunden
Wenn wir bis auf 0 runtergezählt haben, nehmen wir von dem soeben betrachteten Zug das Zielfeld als den Punkt, wohin wir zurück gesetzt werden...
Bis hierhin sollte alles klar sein, oder?
Der 2. Crash - Szenario 1 - Crash nach weniger als ZZZ Zügen
Schritt 4 - Erneut crashen, nach 2 Zügen
Wir fahren nun ganz einfach so schnell wie möglich gegen die Wand. Das schaffen wir nach 2 Zügen, was in userem Beispiel weniger ist als der ZZZ von 4 - und darauf kommt es in diesem Szenario an...
Schritt 5 - Der Algorithmus zählt rückwärts
Hier wird es jetzt spannend!
Wie auch beim ersten Crash zählt der Algorithmus nun von ZZZ=4 runter bis 0. Allerdings findet er diesmal während des Rückwärtsgehenseinen Crash (die rote Linie). An dieser Stelle wird der Zähler ($i) um den ZZZ ($aussetzen) erhöht, so dass wir nun weiter zurückgehen müssen als ursprünglich angenommen, so lange bis wir wirklich bei 0 sind.
Schritt 6 - Crashpunkt gefunden
Wenn wir nun wieder bis auf 0 runtergezählt haben, dann nehmen wir von diesem Zug wieder das Zielfeld als den Punkt, wohin wir zurück gesetzt werden...
Das Ergebnis nehmen wir jetzt erstmal so hin, richtig merkwürdig wird es erst im folgenden Szenario... Ich hoffe aber ihr konntet mir bis hierher folgen!
Der 2. Crash - Szenario 2 - Crash nach genau als ZZZ Zügen
Schritt 4 - Erneut crashen, nach 2 Zügen
Diesmal fahren wir nicht auf dem kürzesten Weg gegen die Wand, sondern nach genau ZZZ Zügen - in unserem Fall also 4.
Schritt 5 - Der Algorithmus zählt rückwärts
Hier wird es jetzt erneut spannend!
Wie auch beim ersten Crash und im ersten Szenario zählt der Algorithmus nun wieder von ZZZ=4 runter bis 0. Allerdings findet er diesmal genau in dem Moment wo er bei 0 angekommen ist einen Crash (die rote Linie). Und anstatt hier nun abzubrechen wird der Zähler ($i) wie auch im ersten Szenario um den ZZZ ($aussetzen) erhöht. Dadurch geht es anschließend weiter in der Historie rückwärst (wir sind ja noch nicht bzw. nicht mehr bei 0), so lange bis wir nochmal bei 0 sind.
Schritt 6 - Crashpunkt gefunden
Wenn wir nun wieder bis auf 0 runtergezählt haben (und dieser zuletzt betrachtete Zug kein Crash war), dann nehmen wir von diesem Zug wieder das Zielfeld als den Punkt, wohin wir zurück gesetzt werden...
mehr Details kommen noch --Ultimate 10:29, 12. Jul. 2014 (CEST)
Der 2. Crash - Szenario 3 - Crash nach mehr als ZZZ Zügen
Im Vergleich zu den vorherigen Szenarien ist das jetzt einfach. Da innerhalb der letzten ZZZ+1 (in unserem Fall 4+1=5) Züge kein Crash war, funktioniert das Zurücksetzen genau so, als wären wir noch gar nicht gecrasht. Daher gehe ich jetzt hier nicht weiter ins Detail.
Der 3. Crash
kommt noch --Ultimate 10:29, 12. Jul. 2014 (CEST)
Bisschen OpenSource
Original-Code von Didi
Da der (zugegebenermaßen evtl. etwas kompliziert programmierte) Algorithmus zur Bestimmung der Zurücksetzposition offenbar einen Bug hat, gibt's hier mal meinen "original"-Source code und danach eine korrektur bzw. Anmerkungen von Quabla.
Ich stell's hier jetzt mal zur Diskussion und möge sich die Community an diesem Stück Code beweisen :-D
if ($possibles==0) { $query="select M_ID,x_pos,y_pos,crash from $movestable [..]"; $res=do_query($query); $maxmoves=mysql_num_rows($res); if ($aussetzen>=$maxmoves) { $aussetzen=$maxmoves-1; } $walker=0; $i=$aussetzen; while ($i>=0) { $row=mysql_fetch_array($res); if ($row[crash]==1) { $sum=$aussetzen+$walker+$i; if (($sum)>=$maxmoves) $i=$maxmoves-$walker-1; else $i=$i+$aussetzen; } $i--; $walker++; } $sysmsg="-:KIch werde $aussetzen Züge zurückgesetztK:-"; echo "AUAAAA! Es quietscht und du knatterst ins Gras... Dafür wirst Du um $aussetzen Züge zurückgesetzt und startest wieder von 0."; }
Kommentare & Korrekturvorschläge
von quabla
Hier die Kommentierung und Vorschläge von Quabla
if ($possibles==0) { $query="select M_ID,x_pos,y_pos,crash from $movestable WHERE [..]"; $res=do_query($query); $maxmoves=mysql_num_rows($res); if ($aussetzen>=$maxmoves) { $aussetzen=$maxmoves-1; }
$walker kann wech
#$walker=0; $i=$aussetzen; while ($i>=0) { $row=mysql_fetch_array($res); if ($row[crash]==1) {
und den ganzen Kladderadatsch in diesem if-Zweig kann man dann ersetzen durch
$i = 0; # $sum=$aussetzen+$walker+$i; # if (($sum)>=$maxmoves) # $i=$maxmoves-$walker-1; # else # $i=$i+$aussetzen; } $i--; #$walker++; }
von Jody
Jody fügt hinzu:
Damit die richtige Anzahl an Zügen ausgegeben wird, müsste man quabla's Vorschlag noch wie folgt ändern:
# ... if ($row[crash]==1) { $aussetzen -= $i; $i = 0; } # ...
von zucker
Zucker: $query="select M_ID,x_pos,y_pos,crash from $movestable [..]"; Liese sich das ganze nicht über EIN sql ziehen und dann einfach einen normalen Zug machen ?
karopapier_singleplayer.zip Da drinn ist auch irgendwo sowas versteckt
von kili
Kili: vorhin schon im Forum verlinkt, aber sicherheitshalber noch mal hier: Bugfix (erzeugte Crashzuege mitzaehlen) und Aufraeumarbeiten (das $walker-Zeugs wird nicht benoetigt):
#... $maxmoves=mysql_num_rows($res); $i=$aussetzen; while ($maxmoves>0 && $i>=0) { $row=mysql_fetch_array($res); if ($row[crash]==1) { $i=$i+$aussetzen+1; } $i--; $maxmoves--; } #...