Freitag, 29. März 2013

Der (Fast-)Mytery "STAUSCHAU"

Eigentlich sollte es ein neuer Mystery werden, aber leider erlauben die (bei mir immer beliebteren :-( ) Guidelines keinen Links auf externe Seiten.
Bevor die stundenlange Arbeit gänzlich umsonst war, möchte ich Euch lieber hier im Blog mit dem Spaß beglücken ein wenig Stauverursacher zu spielen.
Da es keine Dose gibt, kann ich euch zusätzlich zum Spaßfaktor nur mit Erwähnung der drei Plätze hier im Blog ködern. Sobald ihr die Buchstaben A-H durch Experimentieren herausgefunden habt schickt sie mir per eMail. Bitte NICHT als Kommentar posten, wir wollen doch niemanden den Rätselspaß verderben.
STAUSCHAU


Abbildung 1: Noch ist alles im grünen Bereich. Muss wohl außerhalb des Berufverkehrs sein.
Beim Studieren meines Autoclub-Magazins wurde ich auf eine sehr interessante Website aufmerksam. Auf
http://traffic-simulation.de
gibt es die Möglichkeit verschiedene Stauszenarien zu simulieren. Was anfänglich als "Na ja" aussah entpuppte sich schnell zum Suchtfaktor, so dass ich die Seite erst nach Stunden wieder verlassen konnte.
Da kam auch die Idee an diesem Spaß andere teilhaben zu lassen. Um diesen Rätselcache zu lösen, musst du mehrere Szenarien simulieren um die Antworten zu erhalten. Die Aufgaben sind extra so gestellt, dass auch bei mehrmaligen Versuchen eine eindeutige Lösung herauskommt. Solltest du dennoch Probleme haben und zwischen 2 Möglichkeiten schwanken so schick mir ne eMail und ich helfe dir gerne weiter. Bevor es zu den Aufgaben gibt noch zwei Tipps
  • Zur Zeitmessung bzw. zur punktgenauen Änderung der Parameter empfiehlt es sich die Simulationsgeschwindigkeit auf 1-fach herunter zu drehen.
  • Erhöhe die Parameter langsam, wenn z.B das Ergebnis auf 50 genau sein soll, empfiehlt es sich in 10er Schritten die Messwert zu verändern.

Abbildung 2: Kurz vor dem Kollaps: Zuviel Verkehr für zu wenig Straße. Willkommen in der Realität.

Nun aber zur ersten Aufgabe. 25 KFZs, davon 20 % LKWs fahren im Kreis. Die restlichen Parameter auf der Seite bleiben auf den voreingestellten Werten. Nach einiger Zeit entsteht zwangsmäßig der Stau und man kann beobachten, wie er sich rückwärts, also mit dem Uhrzeigersinn bewegt.
A bezeichnet die Zeit in Minuten, die er braucht um eine Runde rückwärts zu vollziehen. Die Antwort soll dabei auf 2 Minuten gerundet sein, also 2, 4, 6, 8, 10, 12 oder 14 Min usw.

B: Nun reduzieren wir die Anzahl der Autos auf 15 und die LWWs auf 1,5 (kleine Transferaufgabe). Wie lange braucht der Stau für die Runde rückwärts nun? Wieder in Zweiminutenschritten.

Kommen wir zum nächsten Scenario, der Zufahrt von Autos auf eine zweispurige Straße.

Die Einstellparameter bleiben auf den Standardwerten von 2800 KFZs pro Stunde auf der Hauptstraße, 400 KFZs, die auffahren und einem zwanzigprozentigen LKW-Anteil. C: Messe die Zeit, bis der Stau auf der Zufahrtsstraße, die Stelle erreicht, wo sich die Zufahrtstraße mit dem Haupt-Zufluss verbindet. Führe die Messung mehrere Male durch um den Mittelwert zu bestimmen und runde wieder auf 2 Minuten.

Stelle den Hauptfluss auf 1000 KFZ, davon 200 LKWs, den Zufluss auf 100 KFZ und starte das Scenarion neu. Ab wie viel Autos Zufluss staut es sich auf der Auffahrt, d.h. die Schlange auf der Zufahrt wird immer länger. Führe den Versuch wieder mehrere Mal durch und runde das Ergebnis D auf 50 KFZ. (50, 100, 150, 200 ....)


Abbildung 3: So sieht es in der Realität meistens aus: Stau und kein Ende in Sicht
Schraube den Zufluss hoch auf das Maximum von 1800 KFZ und lassen den Stau anschwellen. Reduziere danach den Zufluss auf der Auffahrt langsam. Ab wie viel KFZ Zufluss E ist die Auffahrt wieder frei?
Lasse der Zufahrt nach jeder Änderung ausreichend Zeit und drehe langsam herunter. Das Ergebnis ist wieder auf 50 genau anzugeben.
Das ist ja wohl der Gipfel. Und vor dem Gipfel kommt die Steigung

Auch hier bleiben die Standardeinstellungen auf 2800 KFZ und 20% LKW.
Was ist bessere Tempolimit F, d.h. wann breitet sich der Rückstau am langsamsten aus? 40 km/h, 80 km/h, 120 km/h oder frei Fahrt für freie Bürger?

Wir reduzieren die Kfz auf 1800 pro Stunde und setzten das Tempolimit aus, d.h wir setzen es hoch auf 140 km/h.
G: Wie Prozent LKWs verkraftet die Straße noch ohne dass es Stau gibt? (in 10 % Schritten)


Abbildung 4: Und wenn gar nichts hilft, dann wird halt ne Baustelle eingerichtet
Die K*** ist am dampfen und der Stau ist da. (Stelle hierfür den Anteil der LKW auf 100 % und warte bis der Stau angewachsen ist)
Dann aber wird es Samstag Nacht, Geisterstunde, das Wochenendfahrverbot für LKWs greift (schiebe den Prozentregeler auf 0).
Wie löst sich der Stau auf, wenn die Anzahl der Kfz bei 1800 bleibt?
  • direkt? G = 3
  • gar nicht? G = 5
  • erst nach längerer Zeit? G = 1
A B C D E F G H
               
Zum Schluss noch ne Kontrollsumme: Alle Buchstaben zusammen sollten 1081 ergeben.

Donnerstag, 28. März 2013

Die Auslösung von OnDistant kontrollieren

Voraussetzung: Zone als Kreis sowie "Der Einstieg in lua“
In früheren Tutorials berichte ich über die Möglichkeit bei einer punktförmigen Zone die Ereignisse OnProximity und OnDistant zu nutzen. Dabei kam es zu dem Problem, dass OnDistant bereits beim Start des Spieles ausgelöst wird.
Wie sich mittlerweile herausgestellt hat, wird OnDistant genaugenommen nicht beim Start sondern bei der ersten Aktvierung der Zone ausgelöst. (Beim vergangenen Tutorial waren alle betroffenen Zone von Start an aktiv, deswegen der Trugschluss mit OnStart).

Abbildung 1: Bei der ersten Auslösung wird das OnDistant-Events ignoriert
Eine einfache Abfrage ob wir uns in der Startphase befinden reicht also nicht mehr aus. Statt dessen müssen wir für jede Zone pflegen, ob das OnDistant-Event zum ersten Male ausgeführt wird (nämlich weil wir gerade die Zone zum ersten Mal aktivieren) oder ob der Spieler gerade den Proximity-Bereich verlässt, denn für diese Aktion wollen wir OnDistant ja nutzen. Dazu bauen wir uns ein Array namen OnDistantRegistry auf, dessen key aus dem Zonennamen besteht und als Value nil also nix oder der Booleanwert true möglich sind. Es könnte auch 1 oder "TradisSindDoof" als Wert genommen werden. Wichtig ist, dass der Vergleich OnDistantRegistry[zoneName] == nil fehlschlägt und da Boolean nur zwei Werte (true oder false) annehmen kann, verbrauchen wir auch nicht viel Speicher für unsere Registry.
In der Methode skipOnDistantEvent geben wir so true zurück, wenn die Methode zum ersten Mal mit diesem Zonennamen aufgerufen wird, ansonsten false.

Abbildung 2: Zu Beginn des OnDistant-Events fragen wir ab, ob wir abbrechen sollen oder ob der Code ausgeführt wird.
Sobald wir für eine Zone ein OnDistant-Event nutzen wollen, fragen wir zu Beginn ab, ob wir die Befehlsfolge des Events abarbeiten oder ob wir mit return abbrechen. 'Abbrechen' bezieht sich aber nur auf das OnDistant-Event nicht auf das Spiel selbst. Dieser Code muss auch nur in den OnDistant-Events eingesetzt werden, die auch wirklich genutzt werden.
Einen Hacken gibt es aber trotzdem bei dieser Lösung: Die fehlerhafte Auflösung des Events bei Aktivierung erfolgt nur, wenn der Spieler sich nicht in der Zone befindet. Sollte eine Zone aktiviert werden in deren onProximity Bereich der Spieler steht (Zufällig beim Start des Spieles, zwei Zonen überlappen sich, Zonenaktivierung durch Timer oder onClick-Events) so hat dies zur Folge, dass beim ersten Verlassen, besser gesagt Distanzieren von der Zone, die Abarbeitung ausfällt, da es für die Registry der erste Aufruf ist. Aber diese Fälle sind im Normalfall nicht zu erwarten und da dann auch das onProximity-Event nicht immer zuververlässig funktionert, kann der Fehler behoben werdene, indem der Spieler einmal raus und wieder rein in den Proximity-Bereich rennt.

Abbildung 3: Die globalen Events werden immer von den Zonen spezifischen ausgeführt
Diese Möglichkeit der Überprüfung ob das Event ausgeführt werden darf oder nicht, umfasst leider in dieser Form nicht die globalen Events, die automatisch für jede Zone ausgeführt werden sollen. Das liegt daran, dass globale Events ein Kunstgriff von Urwigo sind.
Abb. 3 zeigt die Umsetzung im von Uwrigo erzeugten lua Code. Dabei wird für jedes Event die currentZone definiert (deswegen können wir auch beim Aufruf der Prüfmethode auf die Variable zurückgreifen), dann die Methode mit der globalen Eventdefinition aufgerufen und zum Schluss der Zonenspezifische Code eingefügt. Zeile 352 und 353 sowie 362 und 363 werden automatisch von Urwigo erzeugt.
Man kann jedoch in der globalen Definition (da wo z.Zt lediglich "Globales OnDistant ausgeloest" steht) eine ähnliche Abhandlung wie in skipOnDistantEvent einbauen, nämlich if onDistantRegistry[currentZone] == nil then return end. Wichtig ist hier keine boolean Wert zu setzen ansonsten würde der nächste Aufruf (Zeile 354 bzw. 364) als zweiter Aufruf für die Zone erkannt und true zurückgeliefert.

Ich habe noch ein wenig mit Closures herum experimentiert um den skip-Check komplett in den global Event Teil zu schieben. Leider habe ich noch keine Möglichkeit gefunden, wie man in lua mehrere Methoden mittels return abbrechen kann. Also a() ruft b() auf und ein "return(2)" oder so ähnlich in b soll nicht nur die Methode b verlassen, sondern auch zum Abbruch der Methode a führen. Falls hier jemand weiter weiß, bin ich um einen Tipp sehr dankbar.

Dienstag, 26. März 2013

Wherigo debuggen, auch ohne Simulator

Voraussetzung: Einen Wherigo debuggen

Abbildung 1: Beim Loggen wird sowohl die print-Ausgabe für den Simulator als auch das Logbuch für den GPSr-Betrieb befüllt.
Im ersten Teil des Debug-Tutorial ging es um die Ausgabe mittels print, die nur im Urwigo-Simulator sichtbar ist. Was aber, wenn bestimmte Fehler / zu untersuchende Situationen erst draußen auf dem Oregon vorzufinden sind. Abhilfe gibt es duch ein Item names Logbuch (! Sowohl Name als auch Identifier sollte "Logbuch" lauten).
Da jeder Logeintrag zwei Arbeitsschritte nach sich zieht, lohnt es sich hier eine Methode zu spendieren, die die Arbeit erledigt. Hat auch den Vorteil, dass Erweiterungen an einer einzigen Stelle vorgenommen werden müssen. So kann man kurz vor Veröffentlichung die Zeilen 2 bis 4 auskommentieren und es werden nirgens Logausgaben geschrieben.

Abbildung 2: Der Aufruf im Spiel geht ganz einfach mittels eines Lua User Code Blockes
Die beste Methoden nützt nichts, wenn sie nicht aufgerufen wird. Dies geht ganz einfach wie man in Abb. 2 erkennt. Man kann aber auch in bestehendem lua Code (bei komplexen Projekten besteht das Spiel fast nur noch aus Direktprogrammierung in lua) die log-Zeile einfügen.

Abbildung 3: So siehts aus: In der Abteilung "Gegenstände" ist unser Logbuch zu finden, indem es für jeden Eintrag eine neue Zeile gibt.
Im Spiel haben wir im Inventar bzw. bei den Gegenständen unser Logbuch. Für jedes Ereignis, dass wir mit einer log-Zeile versehen, wird eine neue Zeile einfügt. Dies bewirken die eckigen Klammern um den Zeilenbruch Zeile 3 nach 4. Anders zu der print Ausgabe wird hier aber leserlicher die neueste Zeile unten eingefügt. Wer es andersherum mag, schreibt value .. Logbuch.Description
!Vorsicht mit zu vielen Logausgaben: Das Oregon wird irgendwann ziemlich langsam, wenn zu vielen Zeilen im Logbuch enthalten sind. Da hift nur eins: Oben wieder wegnehmen. string.sub ist hier das Stichwort nach dem man suchen muss. So gibt string.sub(Logbuch.Description, -50) die letzten 50 Zeichen zurück. Wer es ganz genau haben möchte ermittelt mittels string.find die passende Stellen des Zeilenumbruches, aber dafür sollte man Grundkenntnisse in Pattern Matching besitzen.

Freitag, 8. März 2013

Fehlersuche: Ein Wherigo-Projekt debuggen

Voraussetzungen: Zone als Kreis

Abbildung 1: Beim Erreichen der Zone wird eine Debug-Nachricht geschrieben und so der Stand der Variable Punkte kontrolliert.
Wer kennt es nicht, man hat stundenlang den schönsten Programmablauf und Variablen definiert, die ereignisabhänig manipuliert werden, aber beim Testlauf funktioniert es einfach nicht.
Manchmal kann man sich mit MessageBoxen behelfen. Aber das ist recht aufwändig und nicht immer einsetzbar, da MessageBoxen von nachfolgenden Events überlagert werden. Außerdem sind (vergessene) MessageBoxen auch später für den Spieler sichbar.
Wesentlich flexibler ist die Möglichkeit in lua einen print Befehl abzusetzen und so Wert von Variablen oder den Aktivitätsstatus einer Zone abzufragen.
In Abb.1 wird der Wert der Variable Punkte abgefragt um zu kontrollieren, welchen Wert sie an dieser bestimmten Stelle hat.
Wichtig ist, dass die Variable nicht nur den Namen sondern auch den Identifier "Punkte" besitzt, ansonsten müssten wir sie mit "ojbPunkte" ansprechen.

Abbildung 2: So sieht die Ausgabe im Simulator-Testlauf aus.
Wenn wir dann unser Projekt im Urwigo-Simulator starten, können wir im rechten Teil des Fensters auf Lua Debug umschalten um die print-Ausgabe im Bereich Result zu sehen. Im späteren Spiel -z.B auf dem Oregon- ist die Ausgabe nicht sichtbar, da auf dem Bildschirm nur MessageBoxen, Inputs & Co angezeigt werden.

Abbildung 3: Die Zone wurde verlassen. Da Punkte um einen Zähler erhöht wurde, hat die Variable nun den Wert 6
Was wir aber eigentlich testen wollten, war, ob der Wert für Punkte auch wirklich erhöht wird. Um das rauszufinden bauen wir im OnDistant Bereich wieder eine print-Anweisung ein. Und siehe da, beim Verlassen der Zone hat die Variable den Wert "6".
Etwas gewöhnungsbedürftig ist, dass wir "von unten nach oben" lesen müssen, denn die Print-Ausgaben werden nicht unter den bishierigen Text eingefügt, sondern oberhalb. Hier ist es sehr hilfreich nicht nur einfach den Wert der Variablen auszugeben, sondern auch den Kontext ("Zone X betreten", "Timer 1 gestart", usw) anzugeben.
Bitte nicht wundern, wenn in der untersten Zeile die Ausgabe "Punktestand beim Verlassen der Zone A 5" erscheinen sollte. Dies wird am Ende des Tutorials erläutert und kann erstmal ignoriert werden.

Abbildung 4: Man kann auch im Simulator während des Testlaufes Variablen abfragen.
Obwohl die print-Ausgaben nicht im späteren Lauf zu sehen sind, empfiehlt es sich, sie wieder herauszunehmen, wenn das Problem gelöst ist. Bei Abfragen, wo man vorher weiß, dass man sie nur einmal oder nur recht kurz gebraucht werden, oder bei Abfragen die einem während des Simulationslaufes erst einfallen, kann man sich auch des OnTheFly-Modus bedienen.
Dazu hackt man seine Anweisungen einfach in das Type in Lua Statements below Fenster und bekommt sofort die Ausgabe.
Doch Vorsicht: Im Gegensatz zur lua Programmierung im Urwigo-Projekt müssen mehrere Anweisungen durch das Semikolon getrennt werden.

Abbildung 5: Leere Ausgabe? Warum wurde nichts geschrieben?
Für diejenigen die sich über die tostring Methode aus Abb. 4 gewundert haben sei erklärt, dass die String-Konkatenation .. nicht mit Boolean-Werten funktioniert und wir deshalb den Boolean-Wert in einen String-Wert umwandeln müssen.
Bevor wir weitermachen leeren wir das Result Fenster mit einem Klick auf clear.
In Abb. 5 sehen wir was passiert, wenn wir diese Umwandlung weglassen ... nämlich gar nichts. Jedenfalls nichts sichbares. Im "unsichbaren Bereich" bricht die Routine ab. Weiter Anweisungen (z.B. "print(Player.Name);") würden nicht mehr ausgeführt.
Leider erscheint aber auch keine Fehlermeldung was schief gelaufen ist. Jedenfalls erscheit die Fehlermeldung nicht im Vordergrund. Wir können aber trotzdem geziehlt nachforschen warum nichts passiert indem wir auf MessageLog umschalten.
Hier sehen wir direkt, dass es zu einem ERROR gekommen ist. Nach einem Klick auf View Messages können wir die Fehlermeldung auch im Ganzen anschauen und erkennen so, den Grund für den N SCHWARZEN BILDSCHIRM HAB ICH! N SCHWARZEN BILDSCHIRM DAS GANZE WOCHENENDE!!. leeren Bildschirm:
[..] attempt to concatenate field 'Active' (a boolean value)
Als Lösung des Problems haben wir in Abb. 4 die tostring Methoden vor den Boolean-Wert geschaltet, sodass nicht String und Boolean, sondern zwei Strings konkateniert werden.

Abbildung 6: Fehleranlayse in "Message Log"
Wer ganz aufmerksam hinschaut, erkennt noch ein weiteres Problem. Obwohl der Player gerade erst gestartet war (die unteren beiden Zeilen) wird sofort das OnDistant Event auf ZoneA ausgelöst. (Eine Zeile darüber.) Ein Problem dass aus Zone als Kreis bereits bekannt ist. Es soll uns hier aber nicht weiter stören, erklärt aber warum die print-Ausgabe "Punktestand beim Verlassen der Zone A 5" beim Starten des Testlaufes erscheint.

Man kann auf diese Art natürlich nicht nur abfragen, sondern auch manipulieren. Hat man z.B. einen Fehler beim Final behoben und will nicht den ganzen WIG nochmals durchlaufen, kann man mit folgendem Code auch ganz leicht zum Final vorspringen:
Final.Active = true;
Final.Visible = true;

Doch Vorsicht: Manipulierender Code sollte man nur OnTheFly einsetzen, nie im Urwigo-Projekt verankern. Denn das Entfernen des Codes ist schnell vergessen und mit hochgeladen. Dann kann jeder Spieler direkt zum Final vorspringen, was wir natürlich nicht wollen.l
Wenn du dich etwas mehr mit lua-Programmierung beschäftigen möchtest, kann ich dir das "lua Einstiegs-Tutorial“ empfehlen.