Sonntag, 8. Juni 2014

Globaler Code - Teil II

Voraussetzung: "Globaler Code - Teil I“
Nachdem ich den ersten Teil des globalen Code hier im Blog vorgestellt habe, wollte ich mal eben schnell den nächsten Beitrag schreiben wo es um Convenience-Angebote für den Spieler geht. U.a sollen die Finalkoordinaten lesbar ausgegeben werden.
Es dürfte so gut wie jeder WIG-Owner sich schon desöftern über das für uns ungewohnte Dezimalgrad-Format (z.B 50.6651666666667N 7.4682E) bei der Koordinatenverarbeitung in Urwigo geärgert haben.
Als Geocacher ist man ja eher das Grad, Dezimalminuten-Format (N 50° 39.910, E 7° 28.092) gewöhnt sein.
Und wenn man dann noch Koordinaten in lua als Waypoint direkt definiert (Wherigo.ZonePoint(50.6651666666667, 7.4682, 0)) ist die manuelle Hin- und Herrechnerei ziemlich aufwändig. In manchen Fällen ist es empfehlenswert die Koordinaten lesbar auf dem Display auszugeben, z.B. wenn der Final etwas kompliziert zu erreichen ist. Damit man neben dem Wherigo-ZonePoint keine extra String-Version der Koordinaten im Dezimalminuten-Format im Code zu pflegen hat, empfiehlt es sich das ganze automatisch umrechnen zu lassen. Kommt vorallem gut, wenn sich die Location ändert, oder ne neue Location hinzukommt.

Abbildung 1: Koordinaten- bzw. Debug-Pretty-Print
Abb.1 zeigt uns mit buildReadableCoorString eine Helfermethode die genau dies macht. Zunächst wird in Zeile 71 und 72 der Waypoint in den Breiten- und Längengrad aufgesplittet.
Beginnend mit der latitude also dem Breitengrad werden mit math.floor der Vorkommateil, also die Gradzahlen abgeschnitten und abgezogen vom ganzen der Nachkommateil gebildet. (Zeile 74. lat - tmp).
Die Umrechnung des Nachkommateil der Dezimalgrad in Minuten und Dezimalminuten habe ich ausgeglieder da es später beim Längenanteil der Koordinaten wiederverwendet werden kann.
Dabei wird in Zeile 81 der Nachkommaanteil mit 60 multipliziert und auf drei Stellen hinterm Komma gerundet. N 50° 39.9100023347 sähe nicht so gelungen aus. Als Ergebnis würde N 50° 39.91 herauskommen was auch nicht zu 100% korrekt aussieht. Es fehlt die abschießende 0.
Dies geschieht in Zeile 82 wo mit string.format("%.3f", val) auf 3 Stellen hinterm Komma (bzw. Punkt) mit Nullen aufgefüllt wird.
Bleibt noch die Runden-Funktion, die gibt es in lua nämlich nicht fertig. Jedenfalls nicht für Dezimalzahlen. Man kann eine Dezimalzahl auf den Ganzteil abrunden (2.88484 => 2) oder aufrunden (4.127 => 5). Um mathematisch Runden zu können bedient man sich eines Trickes, indem man mit + 0.5 die Rundungsgrenze auf die ganze Zahl verschiebt und dann abrundet.
Bsp.: 2,6 + 0,5 ergäbe 3,1; abgerundet mit math.floor ergibt 3. Gegenbeispiel 2,3 + 0,5 ergibt 2,8; abgerundet auf den Ganzzahlanteil ergibt 2.
mult = 10 ^ (idp or 0) ergibt 1000, da idp mit 3 (Nachkommastellen) übergeben wird. In der Schule haben ja gelernt: Multiplikation mit 10 hoch x heißt das Komma um x Stellen nach rechts verschieben. Aus 0,9100023347 wird dann 910,0023347; das ganze addiert um 0,5 => 910,5023347; auf Ganzzahlanteil abgerundet => 910; Zum Schluss wird das Komma wieder um drei Stellen nach links verschoben, d.h. Division durch 10 hoch 3 = 1000 - ergibt 0,91

Wem jetzt der Schädel wegen zu viel Mathe qualt, der sei beruhigt, das war's mit Mathe, nun kommt nur noch eine Abkürzung für's Debug-Logging.
Wie ich bereits in Einen Wherigo debuggen beschrieben habe, ist es oft ziemlich hilfreich mit print den aktuellen Stand von Variablen auf die Simulatorkonsole zu schreiben.
Da der Informatiker faul ist, ergibt sich die "Notwendigkeit" das mit p abzukürzen.
pt hingegen bringt uns jetzt noch echten Mehrwert, indem vor die Logzeile die aktuelle Uhrzeit geschrieben wird. So kann man leichter zusammenhängende Aktionen erkennen und sich besser durch die Von-Oben-Nach-Unten Syntax des Logfiles wühlen. Es gibt übrigens keine Genauigkeit auf den Millisekundenbereich. Die Sekunde ist die kleinste Zeiteinheit, die ihr im Wherigo messen könnt.
Die Zeilen 95 - 99 beschäftigen sich mit dem Problem, dass man in lua keinen String mit nil oder nem Boolean verknüpfen kann. So ist gesichert, dass in Zeile 101 nur Zahlen und Strings konkateniert werden.

Samstag, 7. Juni 2014

global.lua - Helperfile für oft wiederkehrende Codestellen

Voraussetzung: "Der Einstieg in lua“
Es gibt so manche Aufgaben, die einem ziemlich oft bei der Programmierung begegnen, bzw. man denkt "Diesen Teil müsste man doch abkürzen" können.
So ist z.B die Ausgabe eines Textes mit oder ohne Bild eine recht komplexe Sache wenn man die MessageBox direkt in lua schreiben möchte.
Vorallem wenn nach dem Klick auf OK noch eine weitere Aktion folgen soll.

Auch das Ersetzen von Variablen in Strings (z.B. bei der Übersetzung deines Cartridges in verschiedene Sprachen ist eine Sache, die man nicht bei jedem neuen Wherigo neu schreiben möchte.

Abbildung 1: Einbinden des globales Codes
Zu diesem Zwecke habe ich mir angewöhnt eine global.lua Datei anzulegen, die ich im überordneten Ordner aller Wherigo liegen habe und die von jedem WIG-Projekt genutzt werden kann.
Ein Beispiel:
  • Im Ordner C:\Wherigos liegt die Datei global.lua
  • Im Ordner C:\Wherigo\MeinTestWherigo liegt dann die Projektdatei test.urwigo
  • Im Ordner C:\Wherigo\MeinZweiterWherigo liegt dann entsprechend zweiterWIG.urwigo
Beide Cartridges, sowohl test.urwigo als auch zweiterWIG.urwigo verwenden global.lua aus dem übergeordneten Ordner


Abbildung 2: Auszug aus _cartridge.lua (enthalten im gwz Archiv)
Beim "Bauen" des cartrigdes bzw. beim Erstellen des gwz Archives spielt der Pfad dann keine Rolle mehr, da der Inhalt der externen lua-Datei in die _cartridge.lua hineinkopiert wird

Abbildung 3: Boolean als Text oder Zahl
Nun aber zu den Methoden an sich. Den Anfang machen die Boolean Werte. Dabei ist es mir für debug Zwecke oft hilfreich, wenn der Wert als Zahl oder String zurückgegeben wird, da eine Konkatenation in lua mit verschiedenen Datentypen Probleme bereitet.
"Raetsel 1 geloest: " .. myBoolVar führt zu einem Laufzeitfehler da hier string und boolean nicht miteinander verknüpft werden kann.
"Raetsel 1 geloest: " .. bts(myBoolVar) hingegen funktioniert, da nun zwei Strings verknüpft werden. Die Ausgabe lautet dann "Raetsel 1 geloest: true"
Dass getBoolAsString als bts (boolToString) abgekürzt ist bzw. dass es mal value und mal condition heißt ist historisch gewachsen. Kein guter Stil, wie ich zugeben muss, aber eine Methode umbenennen wird im nachhinein schwierig, da man auch alle Aufrufe der Methode in zahlreichen Wherigo-Projekten anpassen muss.
Also lieber gleich sinnvolle Namen verwenden.

Die dritte Methode wählt zufällig true bzw. false, abhängig von einer Wahrscheinlichkeit.
Bsp: Bei meinem Fußball-Wherigo Heimspiel soll die gegnerische Mannschaft nur in einem von drei Fällen ein Tor schießen.
getRandomBool(33) löst diese Aufgabe. math.random(100) liefert eine Ganzzahl zwischen 1 und 100, also 5, 41, 87 ...
Ist diese Zahl kleiner als unsere Vorgabe 33 wird true zurück geliefert, ansonsten false. Korrekterweise müsste es kleiner gleich heißen, da nicht von 0 bis 99 sondern von 1 bis 100 gezählt wird.


Abbildung 4: Ausgaben vereinfachen
Im zweiten Block geht es um die Ausgabe in Form von MessageBoxen. Da die ersten drei Methoden nur Convenience-Wrapper für die vierte sind, beginnen wir auch bei letzerer in Zeile 38.
Hier wird eine MessageBox aufgebaut, die mit dem übergebenen Text m und einem optionalen Bildchen med gefüllt wird.
Als Callback wird der Teil bezeichnet, der ausgeführt werden soll, wenn der Spieler auf OK gedrückt hat.
Hier wird es jetzt spannend. Lua unterstützt nämlich hier das Konstrukt einer "closure". D.h. es wird eine Methode cf definiert (Zeile 35), die erst dann ausgeführt wird, wenn der MessageBox danach zumute ist.
Woraus besteht aber die Methode cf? Zunächst hat sie einen Parameter action. Ist dieser Parameter null, so geschieht ... rein gar nix. Ich konnte diesen Fall noch nie beobachten. Wahrscheinlich ein Sicherheitscheck, falls man die MessageBox nicht mit "OK", sondern mit dem Back-Button des Smartphones verlässt.
Ruft hingegen die MessageBox die Methode cf(anAction) mit einem Not-Null-Parameter auf, so wird die zweite innere Methode fun (wieder eine closure) ausgeführt.
Was aber ist denn fun ? fun wird von außen definiert, z.B. in Zeile 29, wo der Befehl "Zeige Mainscreen" übergeben wird. Auch hier gilt, in Zeile 29 wird Wherigo.ShowScreen(Wherigo.MAINSCREEN) nur definiert, aber noch nicht ausgeführt. Dies passiert erst, wenn der Spieler in der MessageBox (z.B. "Gehe nun zum Final") auf "OK" drückt.
Achtung: Vergesst nicht bei der Definition der Methode die Schlüsselwörter function() und end. Ansonsten habt ihr keine closure definiert, sondern es wird direkt der Mainscreen angezeigt!
Jetzt wird sich der gewiefte Leser/Entwickler denken "Wozu brauche ich den action Parameter?". Dieser dient theoretisch dazu weitere Informationen an die aufrufende Methode zu übergeben. Man könnte ne Zahl oder einen String reinschreiben. Trotz längerer Studie des von Urwigo kompilierten Codes konnte ich aber stets nur den action ~= nil Vergleich finden.
Man kann allerdings einer MessageBox mehrere Buttons geben und damit einen Quasi-Input generieren. Über action (enthält "Button1" bzw. "Button2") kann man dann unterscheiden welcher Button gedrückt wurde. Ein sinnvolles Szenario wäre "Du bist an der Zone Goldbergwerk angekommen. Die bereits abgebauten Goldklumpen wandern hiermit in dein Inventar", Button1 = "OK", Button2 = "Nachricht zukünftig nicht mehr anzeigen"

Abbildung 5: Debug-Ausgaben, Wegpunkt-Mittelung und String-Operationen
Nun aber genug der komplexen closure-Theorie. Zum Abschluss etwas leichtere Kost.
calcCenterZonePoint liefert euch die GPS-Koordinate, die genau zwischen point1 und point2 liegt. Ist ganz praktisch um die Hälfte der Laufstrecke oder den Mittelpunkt eines Fußballfeldes zu bestimmen.
printTable gibt beim debuggen den Wert einer Tabelle aus. Da jedes "Objekt" in lua als Tabelle definiert ist, kann das schon mal ganz hilfreich sein.
Die Werte einer Zone (Name, Koors, ob aktiv oder nicht...) sind ebenfalls als Tabelle gespeichert und können über getmetatable() abgerufen werden. Als Ergebnis seht ihr beim Debuggen alle Infos über eure Zone.

Zum Schluss noch ein Beispiel für Substitution. Hier wird in einem String "Gehe zur Zone #1# und warte", "Schmiede" der Wert "Gehe zur Zone Schmiede und warte" gebildet. Hilfreich bei Mehrsprachigkeit eures Wherigos.

Freitag, 9. Mai 2014

MEGA Switzerland, wir kommen


MEGA Switzerland, wir kommen !!!

Nachdem es gestern abend noch Anflüge von Panik gab, da das seit November gebuchte Ticket nicht ausgedruckt und die Mail auf dem Rechner mit abgerauchtem Mainboard lag, kam heute morgen die frohe Botschaft: Ein Kopie der eMail mit allen Anmeldedaten und Bestellbestätigung.
Da kann ich nur sagen, tolle Orga.
So geht es in 40 Minuten los Richtung Eidgenossen. Und ein Cachopoly liegt nur wenige Kilometer entfernt....

Sonntag, 20. April 2014

Sprachausgaben übersetzten ohne vararg Parameter

Voraussetzung: "I18n - Einen Wherigo in verschiedenen Sprachen anbieten“


Abbildung 1: Die Übersetzungen mit mehreren Parametern ohne varargs
Im vergangenen Tutorial bzgl. der Übersetzung habe ich den vararg Parameter ... eingesetzt.
Es scheint aber so, dass manche WhereYouGo bzw. PiGo Player Version Probleme mit diesem Konstrukt haben.

Um dem vorzubeugen möchte ich euch folgende Lsg vorstellen, die mir schnuefelis als funktionstüchtig beschrieben hat.

Der Trick ist recht einfach. Anstatt mit ... eine unbestimmte Anzahl an Parameter zu definieren, baut ihr einfach mehrere Methoden, die einen, zwei, oder drei "replacements" akzeptieren.

Um nicht unnötig Code zu duplizieren, rufen diese Methoden alle die 4-Parameter Version auf, in der dann geprüft wird ob replacement1, 2 oder 3 nil sind und nur dann die Ersetzung starten.

Als Softwarentwickler tut eine solche Lösung zwar schon ein bißchen weh, aber bei der Vielzahl der Player mit all ihren Schwächen muss die Dynamik zugunsten der Stabilität leiden.

Freitag, 21. März 2014

"13 Monate ist auch genug"

Heute mal nen ganz kurzer spontaner Beitrag:
Inspiriert durch die erste Notification des Tages
"[GEO] Notify: XXX archived YYY (Traditional Cache)", der Owner archiviert seinen eigenen Cache:

"Log Date: 3/20/2014 Der ist so oft weg, und 13 Monate ist auch genug. Mache wieder Platz für andere..."

Fand ich sehr interessant und brachte mich zum Schmunzeln.
"13 Monate ist auch genug".
Es soll keine Ketzerei gegen den Log oder den Owner sein, nein es zeigte mir einfach wie sich unser Hobby entwickelt hat. Schnell nen Tradi abgelegt, länger als nen Jahr muss er eh nicht halten. Da ich den Owner kenne, glaube ich zwar nicht, dass bei diesem Cache eine solche Überlegung ne Rolle gespielt hat, ich kenne aber genügend andere wo man bei der Publish Notification den Eindruck hat, dass die Dose bewußt so schnell und einfach gelegt hat, dass man gar nicht vor hat den Cache lange aufrecht zu halten.

Ich hoffe ich konnte den Schmunzelfaktor am Morgen an euch weitertragen.

Montag, 10. März 2014

Hier gibt es nix zu sehen

Wirklich, hier gibt es nix zu sehen:
http://muah.info

Sonntag, 9. März 2014

Grill & Kick Wherigo Event

Was haben Grillen und Kicken gemeinsam? Richtig, ab und zu muss man ganz schnell laufen. Man kann die beiden Freizeitbeschäftigungen aber anders verbinden:



Laufe auf einem echten Rasenplatz um einen virtuellen Ball in ein echtes Tor zu schießen und spiele dabei gegen virtuelle Gegner wie z.B. die deutsche Nationalmannschaft

Neugierig? Dann schau dir das Listing an, pack Grillfleisch und den Wherigo-Player ein