PowerShell – Games 01 – Galgenraten / Hangman

Nachdem ich es seit längerem nicht mehr geschafft habe meine bereits angefangenen Artikel zu veröffentlichen (dies leider aus Zeitgründen), hier mal etwas Neues aus der Kategorie ‚Spiele unter PowerShell‘. Um zu zeigen das mit PowerShell auch mehr als nur einfache Abfragen gegen das AD generiert werden können, habe ich hier ein Galgenraten, nicht grafischer Art, geschrieben. Dieses PS Script dient mir als Vorlage für die spätere Version in C#. Gerne kann auch über die Umsetzung und Effizienz des Codes diskutiert werden. Vielleicht gibt es einen besseren oder schöneren Weg? Aber nun erst mal zu meinem Code.

Welche Funktionen und Tools werden seitens PowerShell benötigt?

Grundsätzlich habe ich hier nur Funktionen auf Basis von PowerShell 3.0 genutzt. Dennoch sollte das Script ebenso mit PowerShell 2.0 funktionieren. Auf zusätzliche Cmdleds habe ich gänzlich verzichtet. Folgende Funktionen eines Strings habe ich genutzt:

  • ToUpper()1
  • Contains()1
  • Split()2
  • Replace()2
  • Remove()2
  • ToString()3

1 Diese Funktionen habe ich im Artikel PowerShell – 03.2 – Strings bearbeiten und untersuchen mit […] beschrieben.
2 Die Funktionen zum Bearbeiten eines Strings wurden im Artikel PowerShell – 03 – Strings zerlegen, zuschneiden, Teile ausschneiden, verbinden beschrieben.
3 toString() wandelt einen beispielsweise eine Integer in einen String um.

Es wurden auch Functions (PowerShell – 11 – Funktionen (Functions)) genutzt um zum einen das Script etwas übersichtlicher zu halten und damit sie die Abfrage nach dem Buchstaben wieder selbst aufrunden kann. Sicher hätte das auch mittels Do While Schleifen funktioniert. In meinem Falle reicht aber auch ein einfacher Funktionsaufruf.

Um die Anzahl der Versuche für ein Wort zu generieren habe ich mich einer einfachen Formel (0.3 * Wortlänge) bedient. Da dies zu Gleitkommazahlen führt, muss die Zahlen noch gerundet werden. Dafür nutzte ich die Mathefunktion Round. Dabei wird auf Ganzzahlen gerundet. Anschließend wird geprüft ob der ermittelte Wert unter 4 liegt, dann wird das Ergebnis von 4 Abgezogen und der Überhang anschließend auf die Anzahl der Versuche geschlagen, sodass der Spieler mindestens 4 Versuche pro Wort hat. Um dieses Wirre Kauderwelsch etwas verständlicher zu machen, hier der erste Code-Schnipsel.

Anschließend muss das gesucht Wort, hier im Beispiel soll es PowerShell sein, noch in die für den Spieler gesuchte Form P_________ gebracht werden. Ziel ist es das der Anfangsbuchstabe stehen bleibt, sollte dieser nochmals im Wort vorkommen, soll dieser natürlich auch stehen bleiben, z.B. bei Einkaufszentrum muss das E immer stehen bleiben, also wie folgt E________e____. Dazu wird eine temporäre Variable $Wort_tmp benötigt und eine einfache For-Schleife. Zuerst wird die temporäre Variable dem Wort gleichgesetzt $Wort_tmp = $Wort. In der For-Schleife wird nun geprüft ob der Anfangsbuchstabe nochmals vorkommt.

Ist dies der Fall so wird der aktuelle Wert in der Variable $Wort_tmp durch den Anfangsbuchstaben ersetzt, ist dies jedoch nicht der Fall wird das aktuelle Feld nur ein Unterstrich „_“ ersetzt. Sodas am Ende die Variable $Wort_tmp wie folgt aussieht: P_________.

Ein weiteres Problem war einen Weg zu finden den richtig getippten Buchstaben im Wort korrekt einzusetzen, wenn das Wort wie in unserem Beispiel PowerShell heißt, sieht es für den Spieler wie folgt nun aus P_________. Tippt dieser auf L und mach möchte mit der Funktion Replace() des Strings arbeiten werden alle ‚_‚ durch L ersetzt. Hier musste ich etwas tricksen, dazu habe ich zwei temporäre Variablen genommen.  Tippt der Spieler nun L ein wird nachfolgende Schleife durchlaufen, wenn L im Wort vorhanden ist.

Zuerst wird geprüft ob der gesuchte Buchstabe L enthalten ist, die Zeile dazu:

Ist diese Prüfung wahr, wird ermittelt wie oft der Buchstabe L sich im Wort PowerShell befindet. Die Übereinstimmungen werden in der Variable $Treffer gespeichert.  Leider reicht es hier nicht einfach nur einen Counter hochzählen zulassen, ich benötige die exakte Stelle im Wort PowerShell. Dazu nutze ich eine For-Schleife mit der ich jeden einzelnen Buchstaben mit Wort mit dem gesuchten Buchstaben L vergleiche. Ist diese Prüfung wahr, wird die Variable $Treffer mit dem Wert von $i und einem Semikolon erweitert. Warum jetzt $i? Ganz einfach, $i ist exakt der Wert des Buchstaben im Wort. In Unserem Beispiel ist dies einmal 8 und 9. Position 8 und 9 weil Arrays immer mit 0 Anfangen zu zählen. Anschließend Splitten wir die Variable $Treffer in ein Array und entfernen zuvor das letzte Semikolon. Somit haben wir die genaue Anzahl der Übereinstimmungen und die exakte Position der Buchstaben ermittelt. Dazu dient folgender Code-Schnipsel

Nun müssen wir die Übereinstimmungen noch in das Wort P_________ rein basteln. Dazu benötigen wir die eben ermittelte Anzahl von L und die exakten Positionen sowie zwei temporäre Variablen, einen Counter und eine For-Schleife. Die Variable $Wort_tmp2 wird der Wert von der bereits oben beschriebenen Variable $Wort_tmp übergeben. Dies geschieht aber nicht einfach als $Wort_tmp2 = $Wort_tmp, sonder $Wort_tmp2 = $Wort_tmp[0..$Wort_tmp.Lenth]. Was soll das bedeuten? Ganz einfach, hier wird nicht der String als String übergeben, sondern $Wort_tmp2 wird zu einem Array. So können wir jedes einzelne Feld prüfen und bei einer Übereinstimmung den gesuchten Buchstaben ersetzen. Die zweite temporäre Variable ist $Ausgabe_tmp, diese bildet anschließend die neu gebildete Ausgabe P_______LL. In der For-Schleife passiert dazu folgendes, der aktuelle Wert der Variable $Wort_tmp2 wird immer mit dem Wert von $Treffer_tmp[$j] verglichen. Passt dieser wird der Variable $Ausgabe_tmp der gesuchte Buchstaben, hier  L, hinzugefügt. Gibt es keine Übereinstimmung so wird der Counter $j um eins erhöht und es wird der Wert von $Wort_tmp2 abgehangen, was dann ein Unterstrich „_“ ist. So wird aus dem Array $Wort_tmp2 und dem einzelnen $Buchstaben wieder ein String $Ausgabe_tmp.

Anschließend muss das Ergebnis noch in der Console ausgegeben werden. Ist der gewählte $Buchstabe im Wort, so wird die oben genannte Schleife durchlaufen und es wird kein Lebenspunkt abgezogen. Ist dies nicht der Falle würde die Schleife nicht durchlaufen und gleich das Ergebnis präsentiert werden und natürlich ein Lebenspunkt abgezogen.

Kein Treffer

Nachdem dies geschehen ist, muss geprüft werden ob die Lebenspunkte bei 0 angekommen sind, ist dies der Fall so wird das Spiel mit einer entsprechenden Meldung und dem Exit-Command beendet.

Gehängt

Ebenso muss der gewählte Buchstabe aus dem vorgegebenen ABC entfernt werden, da dieser bereist verwendet wurde.

Um nun den nächsten Buchstaben erraten zu können wird geprüft ob unser Wort $Wort_tmp noch das Zeichen ‚_‘ enthält. Ist der Unterstrich noch enthalten, so gilt das Wort als noch nicht gelöst und die Hauptfunktion Game wird erneut aufgerufen, andern Falls wird die Funktion nicht mehr aufgerufen und eine Meldung „Du hast es geschafft“ ausgegeben und das Spiel ist erfolgreich beendet.

Erfolgreich gelöst

Soweit das Spiel in seinem Grundkonzept. Jetzt kommen wir zu dem wesentlich schwierigeren Teil: Fehler abfangen und das Ganze DAU-sicher machen.

Fehler abfangen und etwas Kosmetik

Was würdet ihr tun, wenn ihr eine solche Consolen-Anwendung vor die Nase gesetzt bekommt? Genau, erstmals kurz stauen und dann so schnell wie möglich alles versuchen damit das Teil abstürzt und bloß nicht das machen was die Anwendung von mir will. Um die Anfälligkeit der Anwendung gegen solche Versuche etwas zu minimieren habe ich folgendes unternommen.

Prüfen der Inputliste

Als erstes wird geprüft, ob die Wörterliste geladen werden kann. Dies läuft in einer Funktion, da diese sich wieder selbst aufrufen, sollte die Liste nicht erreichbar sein. Das Ganze ist einfach mittels Try-Catch realisiert. Es wird einfach versucht die angegebene Liste mittels Get-Content zu laden, schlägt dies Fehl springt das Script in den Catch-Fall und bittet den Benutzer mittels Read-Host den korrekten Pfad zur Wortliste anzugeben. Dieser Vorgang wird solange widerholt, bis entweder die Liste erreichbar ist oder der Benutzer ‚exit‘ eingibt. In diesem Falle wird das Script beendet. Ist dieser Schritt geschafft geht es auch schon daran die Eingabe des Spielers zu überwachen.

Inputliste laden

 Prüfen der eingabe

Geprüft wird die Eingabe. Hier habe ich die Länge der Eingabe auf 1 Zeichen beschränkt zudem dürfen Sonderzeichen wie +,*,\,/,$ etc. nicht enthalten sein, diese wird alles in die If-Abfrage gepackt.

Eingabe des Buchstaben

Geprüft werden muss auch, ob der gewählte Buchstabe noch im vorgegebenen Alphabet  $ABC vorhanden ist. Ist der Buchstabe nicht mehr enthalten, so wird eine Ausgabe erzeugt, die den Spieler auffordert einen anderen Buchstaben einzugeben.

Bereits verwendet

Noch etwas kosmetik

Damit die Ausgabe der Console nicht in einem Farblosen Schriftberg untergeht, habe ich hier mittels der Eigenschaften von Write-Host etwas Farbe rein gebracht.
Das Script könnt ihr euch hier nochmal im Ganzen anschauen. Ebenso könnt ihr es hier downloaden mit meiner äußerst kreativen Wortliste ;). Dann bitte einfach noch den String  $WortPfad anpassen.

Wer noch Ideen, Anregungen oder Fragen zum Code hat oder Verbesserungen sieht, darf sich gerne melden 🙂

[wpfilebase tag=file id=6 /]

rewe

Script komplett, leider musste ich die Formatierung etwas anpassen, da der Interpreter hier sonst etwas Murks macht.

 

Ein Gedanke zu „PowerShell – Games 01 – Galgenraten / Hangman“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert