(ab Klasse 5, ohne Mathematik)
Wir programmieren das Spiel "Stein-Papier-Schere" als Zwei-Personen-Konsolen-Spiel mit Python.
Erst wird das fertige Programm vorgeführt. Dann programmiert jeder selber.
Die folgenden Code-Beispiele am besten selber abtippen.
1. Minimales Programm
Schau dir in der Python-Referenz unter "Aufbau py-Datei" an wie man ein minimales Programm schreibt.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ print("Hallo zum Stein-Papier-Schere-Spiel.") print("Mehr gibt es hier noch nicht.")
Den Code in eine Datei speichern und laufen lassen.
Übung
-
Lasse das Programm noch etwas anderes ausgeben.
-
Versuche, etwas zu "zeichnen", z. B. einen Kasten.
2. Zwei Spieler
Das Spiel soll mit zwei Spielern gespielt werden. Die beiden Spielernamen geben wir auf der Konsole aus.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ print("------------------------------------") print("Hallo zum Stein-Papier-Schere-Spiel.") print("------------------------------------") print("") # spieler1 ist eine Variable. # "Kurt" steht in Anführungszeichen und ist somit eine Zeichenkette. # Durch das das Gleichzeichen (=) wird der Wert auf rechten Seite ("Kurt") # der Variablen auf der linken Seite zugewiesen. spieler1 = "Kurt" spieler2 = "Lea" print("Spieler 1 Spieler 2") # Die format-Funktion arbeitet auf Zeichenketten. print("{0} {1}".format(spieler1, spieler2)) print("")
Neue Begriffe: Zeichenkette, Variable, Zuweisung
Übung
-
Programmiere den Spieltitel in eine Variable und ändere ihn ab.
3. Tasten
Jeder Spieler soll Tasten bekommen. Im ersten Schritt zeigen wir diese Tasten erst einmal nur auf der Konsole an und fügen Test-Code für die Tastenbehandlung ein.
Den neuen kompliziert aussehenden Code-Abschnitt im oberen Teil muss man erst mal nicht verstehen; hier am besten Kopieren&Einfügen.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys ############################################################################### ### Damit wir Tasten auslesen können. ### class _Getch: # found on http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/ """Gets a single character from standard input. Does not echo to the screen.""" def __init__(self): try: self.impl = _GetchWindows() except ImportError: self.impl = _GetchUnix() def __call__(self): return self.impl() class _GetchUnix: def __init__(self): import tty, sys def __call__(self): import sys, tty, termios fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(sys.stdin.fileno()) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ch class _GetchWindows: def __init__(self): import msvcrt def __call__(self): import msvcrt return msvcrt.getch() getch = _Getch() ############################################################################### print("------------------------------------") print("Hallo zum Stein-Papier-Schere-Spiel.") print("------------------------------------") print("") spieler1 = "Kurt" spieler2 = "Lea" print("Spieler 1 Spieler 2") print("{0} {1}".format(spieler1, spieler2)) print("") print("Es gelten folgende Tasten:") print("") print("A = Stein J = Stein") print("S = Schere K = Schere") print("D = Papier L = Papier") print("") print("Tastentest \n - Jeder Spieler drückt seine Tasten (gerne auch ungültige Tasten):") print(" - Q zum Beenden") print("") # while True ist eine Unendlichschleife. while True: k = getch() print("Taste: " + k) if k == 'q': break
Übung
-
Ändere das Programm, indem du unten das k = getch() durch k = "Hallo" ersetzt. (Man kann ein Programm übrigens mit Strg+C abbrechen.)
-
Mache die Änderung aus 1. rückgängig. Ändere das Programm so, dass es auch bei der Taste X abbricht.
-
Was passiert, wenn man ein großes X (also Umschalt+X) drückt?
-
Entferne die while-Anweisung (und rücke den Code um eine Stufe nach links). Was passiert?
Neue Begriffe: Schleife, if-Anweisung, Vergleichsoperator
4a. Listen
Listen am Beispiel einer Einkaufsliste.
einkaufsliste = [ "Äpfel", "Birnen", "Haferflocken", "Haselnüsse" ] print("Ich kaufe heute folgendes ein: {0}".format(einkaufsliste)) print("Meine Einkaufsliste hat {0} Einträge.".format(len(einkaufsliste))) einkaufsliste = einkaufsliste + [ "Aprikosen" ] print(einkaufsliste) einkaufsliste.append("Kakaopulver") print(einkaufsliste) print(einkaufsliste[0]) print(einkaufsliste[1]) print(einkaufsliste[2]) print(einkaufsliste[3]) i = 0 while i < len(einkaufsliste): print(einkaufsliste[i]) i = i + 1 for eintrag in einkaufsliste: print(eintrag) einkaufsliste.remove("Birnen") print(einkaufsliste) del einkaufsliste[0] print(einkaufsliste)
4b. Funktionen
…
4c. Programm umschreiben
Wir schreiben das Programm folgendermaßen um:
-
Jedes Objekt (Stein, Papier, Schere) bekommt eine Zahl, nämlich 0, 1 und 2 → mit Hilf der Liste objekte
-
Die Tasten für jeden der Spieler wird in einer Liste von Listen definiert → Variable tasten
-
Die Spieler werden in einer Liste gespeichert → Variable spieler
-
Die Info-Ausgabe für die Tasten wird mit Hilfe der Variablen objekte und tasten umgesetzt.
-
Es gibt eine neue Funktion taste_zu_spieler, die zu einer gegebenen Taste ausgibt, zu welchem Spieler sie gehört.
-
Tastentest: zu jeder Tasten wird nun ausgegeben, zu welchem Spieler sie gehört.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys ############################################################################### ### Damit wir Tasten auslesen können. ### class _Getch: # found on http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/ """Gets a single character from standard input. Does not echo to the screen.""" def __init__(self): try: self.impl = _GetchWindows() except ImportError: self.impl = _GetchUnix() def __call__(self): return self.impl() class _GetchUnix: def __init__(self): import tty, sys def __call__(self): import sys, tty, termios fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(sys.stdin.fileno()) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ch class _GetchWindows: def __init__(self): import msvcrt def __call__(self): import msvcrt return msvcrt.getch() getch = _Getch() ############################################################################### ### Globale Variablen objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D' ], [ 'J', 'K', 'L' ] ] ############################################################################### ### Funktionen ### def taste_zu_spieler(k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 ############################################################################### print("------------------------------------") print("Hallo zum Stein-Papier-Schere-Spiel.") print("------------------------------------") print("") spieler1 = "Kurt" spieler2 = "Lea" spieler = [ spieler1, spieler2 ] print("Spieler 1 Spieler 2") print("{0} {1}".format(spieler[0], spieler[1])) print("") print("Es gelten folgende Tasten:") print("") print("{0} = {1} {2} = {3}".format(tasten[0][0], objekte[0], tasten[1][0], objekte[0])) print("{0} = {1} {2} = {3}".format(tasten[0][1], objekte[1], tasten[1][1], objekte[1])) print("{0} = {1} {2} = {3}".format(tasten[0][2], objekte[2], tasten[1][2], objekte[2])) print("") print("Tastentest \n - Jeder Spieler drückt seine Tasten (gerne auch ungültige Tasten):") print(" - Q zum Beenden") print("") while True: k = getch() print("Taste: " + k) s = taste_zu_spieler(k) if s >= 0: print("Die Taste gehört zu {0}".format(spieler[s])) if k == 'q': print("Beenden...") break
Übung
-
Schreibe eine eigene Funktion, die einige der print-Ausgaben kapselt.
-
Was macht die verwendete Funktion upper(), wenn man sie auf eine Zeichenkette anwendet? Und was macht lower()?
5. Code auslagern
-
Wir lagern den getch-Code in eine eigene Datei aus. → getch.py
-
Zu jeder gedrückten Taste wird nun der Spieler und das Objekt angezeigt.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys from getch import * ############################################################################### ### Globale Variablen objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D' ], [ 'J', 'K', 'L' ] ] ############################################################################### ### Funktionen ### def taste_zu_spieler(k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 def taste_zu_objekt(k): k = k.upper() # Großbuchstabe if k in tasten[0]: return tasten[0].index(k) elif k in tasten[1]: return tasten[1].index(k) else: return -1 ############################################################################### print("------------------------------------") print("Hallo zum Stein-Papier-Schere-Spiel.") print("------------------------------------") print("") spieler1 = "Kurt" spieler2 = "Lea" spieler = [ spieler1, spieler2 ] print("Spieler 1 Spieler 2") print("{0} {1}".format(spieler[0], spieler[1])) print("") print("Es gelten folgende Tasten:") print("") print("{0} = {1} {2} = {3}".format(tasten[0][0], objekte[0], tasten[1][0], objekte[0])) print("{0} = {1} {2} = {3}".format(tasten[0][1], objekte[1], tasten[1][1], objekte[1])) print("{0} = {1} {2} = {3}".format(tasten[0][2], objekte[2], tasten[1][2], objekte[2])) print("") print("Tastentest \n - Jeder Spieler drückt seine Tasten (gerne auch ungültige Tasten):") print(" - Q zum Beenden") print("") while True: k = getch() s = taste_zu_spieler(k) if s >= 0: o = taste_zu_objekt(k) print("Die Taste gehört zum {0} von {1}".format(objekte[o], spieler[s])) else: print("Taste: " + k) if k == 'q': print("Beenden...") break
Übung
-
Gegeben folgende Liste: a = [ 39, 0, 28, 29, 30, 5, 7, 8 ]. Was liefert der Funktionsaufruf a[2]? Und was a.index(28)?
-
Man kann Listen auch verschachteln: a = [ 1, 2, 3 ], b = [ 10, 20, 30 ], c = [ a, b ]. Was liefert c[0][2]?
6. Spielverlauf, Logik
-
Ein einfacher Spielverlauf wird umgesetzt nach dem Muster "Achtung, Fertig, Los".
-
Zur Prüfung, ob zwei gedrückte Tasten zu unterschiedlichen Spielern gehören, werden Vergleichs- (>=) und boolsche Operatoren (and) verwendet.
-
Die Tastenlegende wurde mit einer Schleife umgesetzt.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys from getch import * ############################################################################### ### Globale Variablen objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D' ], [ 'J', 'K', 'L' ] ] ############################################################################### ### Funktionen ### def taste_zu_spieler(k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 def taste_zu_objekt(k): k = k.upper() # Großbuchstabe if k in tasten[0]: return tasten[0].index(k) elif k in tasten[1]: return tasten[1].index(k) else: return -1 def ready(): print("Ready...") k0 = getch() k1 = getch() s0 = taste_zu_spieler(k0) s1 = taste_zu_spieler(k1) if s0 >= 0 and s1 >= 0 and s0 != s1: print(" OK") else: print("!Ungültig!") def fight(): print("Go...") k0 = getch() k1 = getch() s0 = taste_zu_spieler(k0) s1 = taste_zu_spieler(k1) if s0 >= 0 and s1 >= 0 and s0 != s1: obj0 = taste_zu_objekt(k0) obj1 = taste_zu_objekt(k1) if s0 == 1: swap = obj1 obj1 = obj0 obj0 = swap print(" {0} {1}".format(spieler[0], spieler[1])) print(" # {0} # # {1} #".format(objekte[obj0], objekte[obj1])) else: print("!Ungültig!") ############################################################################### print("------------------------------------") print("Hallo zum Stein-Papier-Schere-Spiel.") print("------------------------------------") print("") spieler1 = "Kurt" spieler2 = "Lea" spieler = [ spieler1, spieler2 ] print("Spieler 1 Spieler 2") print("{0} {1}".format(spieler[0], spieler[1])) print("") print("Es gelten folgende Tasten:") print("") for i in range(3): print("{0} = {1} {2} = {3}".format(tasten[0][i], objekte[i], tasten[1][i], objekte[i])) print("") print("Spielverlauf:") print(" - Jeder Spieler drückt eine seiner Tasten zur Vorbereitung.") print(" - Jeder Spieler nochmal drückt eine seiner Tasten zur Vorbereitung.") print(" - Jeder Spieler drückt die Taste, mit der er seinen Gegenspieler herausfordert.") print("") ready() ready() fight()
Übung
-
Was fällt bei der Ausgabe der neuen Tastenlegende auf?
-
An welcher Stelle im Code werden die Werte von zwei Variablen getauscht und warum?
-
Gebe anstatt "Ready…", "Ready…", "Go…", "Schnick…", "Schnack…", "Schnuck!!!" aus, indem du die ready()-Funktion parametrisierst.
7. Gewinnauswertung
Am Ende wird angezeigt, wer gewonnen hat und warum.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys from getch import * ############################################################################### ### Globale Variablen objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D' ], [ 'J', 'K', 'L' ] ] ############################################################################### ### Funktionen ### def taste_zu_spieler(k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 def taste_zu_objekt(k): k = k.upper() # Großbuchstabe if k in tasten[0]: return tasten[0].index(k) elif k in tasten[1]: return tasten[1].index(k) else: return -1 def gewinn_aktion(obj0, obj1): """ Liefert den Text wie obj0 über obj1 gewinnt. Wenn obj0 gegenüber obj1 verliert, wird "ungültig" geliefert """ if obj0 == 0 and obj1 == 2: return "Stein macht Schere stumpf." if obj0 == 1 and obj1 == 0: return "Papier umwickelt Stein." if obj0 == 2 and obj1 == 1: return "Schere zerschneidet Papier." return "ungültig" def auswertung(obj0, obj1): """ obj0 gehört zu spieler0. obj1 gehört zu spieler1. Liefert zurück, wer gewonnen hat (0 oder 1) oder -1 für unentschieden """ if obj0 == 0 and obj1 == 2 or obj0 == 1 and obj1 == 0 or obj0 == 2 and obj1 == 1: return 0 elif obj1 == 0 and obj0 == 2 or obj1 == 1 and obj0 == 0 or obj1 == 2 and obj0 == 1: return 1 else: return -1 def ready(): print("Ready...") k0 = getch() k1 = getch() s0 = taste_zu_spieler(k0) s1 = taste_zu_spieler(k1) if s0 >= 0 and s1 >= 0 and s0 != s1: print(" OK") else: print("!Ungültig!") def fight(): print("Go...") k0 = getch() k1 = getch() s0 = taste_zu_spieler(k0) s1 = taste_zu_spieler(k1) if s0 >= 0 and s1 >= 0 and s0 != s1: obj0 = taste_zu_objekt(k0) obj1 = taste_zu_objekt(k1) if s0 == 1: swap = obj1 obj1 = obj0 obj0 = swap print(" {0} {1}".format(spieler[0], spieler[1])) print(" # {0} # # {1} #".format(objekte[obj0], objekte[obj1])) s = auswertung(obj0, obj1) if s >= 0: ga = None if s == 0: ga = gewinn_aktion(obj0, obj1) else: ga = gewinn_aktion(obj1, obj0) print(" __{0}__ hat gewonnen, denn {1}".format(spieler[s], ga)) else: print(" UNENTSCHIEDEN") else: print("!Ungültig!") ############################################################################### print("------------------------------------") print("Hallo zum Stein-Papier-Schere-Spiel.") print("------------------------------------") print("") spieler1 = "Kurt" spieler2 = "Lea" spieler = [ spieler1, spieler2 ] print("Spieler 1 Spieler 2") print("{0} {1}".format(spieler[0], spieler[1])) print("") print("Es gelten folgende Tasten:") print("") for i in range(3): print("{0} = {1} {2} = {3}".format(tasten[0][i], objekte[i], tasten[1][i], objekte[i])) print("") print("Spielverlauf:") print(" - Jeder Spieler drückt eine seiner Tasten zur Vorbereitung.") print(" - Jeder Spieler nochmal drückt eine seiner Tasten zur Vorbereitung.") print(" - Jeder Spieler drückt die Taste, mit der er seinen Gegenspieler herausfordert.") print("") ready() ready() fight()
Übung
-
Der Code ist etwas komplizierter geworden. Füge print-Anweisungen hinzu, wenn etwas unklar ist.
8. Spieler-Namen und Punkte
-
Die Namen der Spieler sind nun variabel. Sie können nun entweder als Kommandozeilenargumente übergeben werden (siehe Python-Referenz unter "Kommandozeilen-Argumente") oder werden nach Programmstart eingegeben.
-
Die Ausgabe wird besser formatiert, damit auch unterschiedliche lange Namen gut ausgegeben werden.
-
Es werden nun 3 Runden hintereinander gespielt und der Punktestand wird gezählt.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys from getch import * ############################################################################### ### Globale Variablen objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D' ], [ 'J', 'K', 'L' ] ] punkte = [ 0, 0 ] ############################################################################### ### Funktionen ### def taste_zu_spieler(k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 def taste_zu_objekt(k): k = k.upper() # Großbuchstabe if k in tasten[0]: return tasten[0].index(k) elif k in tasten[1]: return tasten[1].index(k) else: return -1 def gewinn_aktion(obj0, obj1): """ Liefert den Text wie obj0 über obj1 gewinnt. Wenn obj0 gegenüber obj1 verliert, wird "ungültig" geliefert """ if obj0 == 0 and obj1 == 2: return "Stein macht Schere stumpf." if obj0 == 1 and obj1 == 0: return "Papier umwickelt Stein." if obj0 == 2 and obj1 == 1: return "Schere zerschneidet Papier." return "ungültig" def auswertung(obj0, obj1): """ obj0 gehört zu spieler0. obj1 gehört zu spieler1. Liefert zurück, wer gewonnen hat (0 oder 1) oder -1 für unentschieden """ if obj0 == 0 and obj1 == 2 or obj0 == 1 and obj1 == 0 or obj0 == 2 and obj1 == 1: return 0 elif obj1 == 0 and obj0 == 2 or obj1 == 1 and obj0 == 0 or obj1 == 2 and obj0 == 1: return 1 else: return -1 def ready(): print("Ready... ", end="") sys.stdout.flush() # damit die Ausgabe sofort erscheint k0 = getch() k1 = getch() s0 = taste_zu_spieler(k0) s1 = taste_zu_spieler(k1) if s0 >= 0 and s1 >= 0 and s0 != s1: print("OK\n") else: print("!Ungültig!") def fight(): print("Go...") print("") k0 = getch() k1 = getch() s0 = taste_zu_spieler(k0) s1 = taste_zu_spieler(k1) if s0 >= 0 and s1 >= 0 and s0 != s1: obj0 = taste_zu_objekt(k0) obj1 = taste_zu_objekt(k1) if s0 == 1: swap = obj1 obj1 = obj0 obj0 = swap print("{0:40}{1:40}".format(spieler[0], spieler[1])) print("{0:40}{1:40}".format("v", "v")) print("{0:40}{1:40}".format(objekte[obj0], objekte[obj1])) print("-" * 80) s = auswertung(obj0, obj1) if s >= 0: # Punktestand anpassen punkte[s] = punkte[s] + 1 ga = None if s == 0: ga = gewinn_aktion(obj0, obj1) else: ga = gewinn_aktion(obj1, obj0) print(">> {0} hat gewonnen, denn {1}".format(spieler[s], ga)) else: print(">> UNENTSCHIEDEN") print(" Punktestand:") print("{0:40}{1:40}".format(spieler[0] + " ({0})".format(punkte[0]), spieler[1] + " ({0})".format(punkte[1]))) else: print("!Ungültig!") def hole_spielernamen(): spieler0 = None spieler1 = None if len(sys.argv) == 3: spieler0 = sys.argv[1] spieler1 = sys.argv[2] else: print("Bitte Namen per Hand eintragen.") spieler0 = input("Spieler 1: ") spieler1 = input("Spieler 2: ") print("") return [ spieler0, spieler1 ] ############################################################################### print(" ------------------------------------") print(" Hallo zum Stein-Papier-Schere-Spiel.") print(" ------------------------------------") print("") spieler = hole_spielernamen() print("{0:40}{1:40}".format("Spieler 1", "Spieler 2")) print("{0:40}{1:40}".format("---------", "---------")) print("{0:40}{1:40}".format(spieler[0], spieler[1])) print("") print(" Tasten:\n") for i in range(3): print("{0} = {1:36}{2} = {3:36}".format(tasten[0][i], objekte[i], tasten[1][i], objekte[i])) print("") print("Spielverlauf:") print(" 1. Jeder Spieler drückt eine seiner Tasten zur Vorbereitung.") print(" 2. Nochmal Vorbereitung") print(" 3. Jeder Spieler drückt die Taste, mit der er seinen Gegenspieler herausfordert.") print("") for i in range(3): ready() ready() fight() print("")
Übung
-
Wenn man der interaktiven Namenseingabe nichts eingibt, bleibt der Name leer. Sorge dafür, dass der Benutzer solange wiederholt gefragt wird, bis der Name nicht leer ist.
-
Wenn jemand gewinnt, bekommt er einen Punkt. Verteile die Punkte anders: Wer gewinnt, bekommt 5 Punkte, wer verliert, bekommt 2 Punkte abgezogen, bei unentschieden gibt es je 1 Punkt.
-
Frage den Benutzer vorher, wieviele Runden gespielt werden sollen.
9. Piktogramme
-
Finde ein Bild mit Piktogrammen von Schere, Stein und Papier, z. B. picto-1
-
Bearbeite es z. B. mit kolourpaint so,
-
dass es einen weißen Hintergrund hat
-
die Rahmen weg sind
-
und das Format jpg ist, z. B. picto-2
-
-
Installiere das Programm jp2a mittels software.opensuse.org.
-
Verwende den Befehl jp2a -i --height=25 bild.jpg, um die Piktogramme in ASCII-Art (engl. art = Kunst) umzuwandeln.
-
Speichere jedes der Symbole in eine eigene Datei: schere.txt, stein.txt, papier.txt.
-
Hierbei kann der "Block Selection Mode" von Kate helfen.
-
-
Das Programm wird nun so geändert, dass die Bilder aus den Dateien geladen und angezeigt werden, wenn ein Spieler gewonnen hat.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys import os from getch import * ############################################################################### ### Funktionen ############################################################################### def taste_zu_spieler(tasten, k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 def taste_zu_objekt(tasten, k): k = k.upper() # Großbuchstabe if k in tasten[0]: return tasten[0].index(k) elif k in tasten[1]: return tasten[1].index(k) else: return -1 def gewinn_aktion(obj0, obj1): """ Liefert den Text wie obj0 über obj1 gewinnt. Wenn obj0 gegenüber obj1 verliert, wird "ungültig" geliefert """ if obj0 == 0 and obj1 == 2: return "Stein macht Schere stumpf." if obj0 == 1 and obj1 == 0: return "Papier umwickelt Stein." if obj0 == 2 and obj1 == 1: return "Schere zerschneidet Papier." return "ungültig" def auswertung(obj0, obj1): """ obj0 gehört zu spieler0. obj1 gehört zu spieler1. Liefert zurück, wer gewonnen hat (0 oder 1) oder -1 für unentschieden """ if obj0 == 0 and obj1 == 2 or obj0 == 1 and obj1 == 0 or obj0 == 2 and obj1 == 1: return 0 elif obj1 == 0 and obj0 == 2 or obj1 == 1 and obj0 == 0 or obj1 == 2 and obj0 == 1: return 1 else: return -1 def ready(tasten): print("Ready... ", end="") sys.stdout.flush() # damit die Ausgabe sofort erscheint k0 = getch() k1 = getch() s0 = taste_zu_spieler(tasten, k0) s1 = taste_zu_spieler(tasten, k1) if s0 >= 0 and s1 >= 0 and s0 != s1: print("OK\n") else: print("!Ungültig!") def fight(tasten, spieler, objekte, punkte, bilder): print("Go...") print("") k0 = getch() k1 = getch() s0 = taste_zu_spieler(tasten, k0) s1 = taste_zu_spieler(tasten, k1) if s0 >= 0 and s1 >= 0 and s0 != s1: obj0 = taste_zu_objekt(tasten, k0) obj1 = taste_zu_objekt(tasten, k1) if s0 == 1: swap = obj1 obj1 = obj0 obj0 = swap print("{0:40}{1:40}".format(spieler[0], spieler[1])) print("{0:40}{1:40}".format("v", "v")) print("{0:40}{1:40}".format(objekte[obj0], objekte[obj1])) print("-" * 80) s = auswertung(obj0, obj1) if s >= 0: if s == 0: print_bild(bilder, obj0, 0) else: print_bild(bilder, obj1, 40) # Punktestand anpassen punkte[s] = punkte[s] + 1 ga = None if s == 0: ga = gewinn_aktion(obj0, obj1) else: ga = gewinn_aktion(obj1, obj0) print(">> {0} hat gewonnen, denn {1}".format(spieler[s], ga)) else: print(">> UNENTSCHIEDEN") print(" Punktestand:") print("{0:40}{1:40}".format(spieler[0] + " ({0})".format(punkte[0]), spieler[1] + " ({0})".format(punkte[1]))) else: print("!Ungültig!") def hole_spielernamen(): spieler0 = None spieler1 = None if len(sys.argv) == 3: spieler0 = sys.argv[1] spieler1 = sys.argv[2] else: print("Bitte Namen per Hand eintragen.") spieler0 = input("Spieler 1: ") spieler1 = input("Spieler 2: ") print("") return [ spieler0, spieler1 ] def lade_bilder(): bilder = [] with open('sp-data/stein.txt') as f: bilder.append(f.read()) with open('sp-data/papier.txt') as f: bilder.append(f.read()) with open('sp-data/schere.txt') as f: bilder.append(f.read()) return bilder def print_bild(bilder, obj, offset = 0): if offset == 0: print(bilder[obj]) else: bild = bilder[obj] zeilen = bild.split(os.linesep) for z in zeilen: print(" " * offset + z) ############################################################################### ### main ############################################################################### def main(): print(" ------------------------------------") print(" Hallo zum Stein-Papier-Schere-Spiel.") print(" ------------------------------------") print("") objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D' ], [ 'J', 'K', 'L' ] ] punkte = [ 0, 0 ] bilder = lade_bilder() spieler = hole_spielernamen() print("{0:40}{1:40}".format("Spieler 1", "Spieler 2")) print("{0:40}{1:40}".format("---------", "---------")) print("{0:40}{1:40}".format(spieler[0], spieler[1])) print("") print(" Tasten:\n") for i in range(3): print("{0} = {1:36}{2} = {3:36}".format(tasten[0][i], objekte[i], tasten[1][i], objekte[i])) print("") print("Spielverlauf:") print(" 1. Jeder Spieler drückt eine seiner Tasten zur Vorbereitung.") print(" 2. Nochmal Vorbereitung") print(" 3. Jeder Spieler drückt die Taste, mit der er seinen Gegenspieler herausfordert.") print("") ready(tasten) ready(tasten) fight(tasten, spieler, objekte, punkte, bilder) print("") if __name__ == "__main__": main()
Übung
-
Zeige zwei der Bilder nebeneinander an.
10. Punktestand merken, Klassen
-
Der Punktestand jedes Spielers soll in einer Datei gespeichert werden, sodass bei Neustart des Programms der Punktestand wiederhergestellt werden kann.
-
Das Laden und Speichern wird mit Hilfe einer Klasse gekapselt.
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys import os import pickle from getch import * ############################################################################### ### Funktionen ############################################################################### def taste_zu_spieler(tasten, k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 def taste_zu_objekt(tasten, k): k = k.upper() # Großbuchstabe if k in tasten[0]: return tasten[0].index(k) elif k in tasten[1]: return tasten[1].index(k) else: return -1 def gewinn_aktion(obj0, obj1): """ Liefert den Text wie obj0 über obj1 gewinnt. Wenn obj0 gegenüber obj1 verliert, wird "ungültig" geliefert """ if obj0 == 0 and obj1 == 2: return "Stein macht Schere stumpf." if obj0 == 1 and obj1 == 0: return "Papier umwickelt Stein." if obj0 == 2 and obj1 == 1: return "Schere zerschneidet Papier." return "ungültig" def auswertung(obj0, obj1): """ obj0 gehört zu spieler0. obj1 gehört zu spieler1. Liefert zurück, wer gewonnen hat (0 oder 1) oder -1 für unentschieden """ if obj0 == 0 and obj1 == 2 or obj0 == 1 and obj1 == 0 or obj0 == 2 and obj1 == 1: return 0 elif obj1 == 0 and obj0 == 2 or obj1 == 1 and obj0 == 0 or obj1 == 2 and obj0 == 1: return 1 else: return -1 def ready(tasten): print("Ready... ", end="") sys.stdout.flush() # damit die Ausgabe sofort erscheint k0 = getch() k1 = getch() s0 = taste_zu_spieler(tasten, k0) s1 = taste_zu_spieler(tasten, k1) if s0 >= 0 and s1 >= 0 and s0 != s1: print("OK\n") else: print("!Ungültig!") def fight(tasten, spieler, objekte, punkte, bilder): print("Go...") print("") k0 = getch() k1 = getch() s0 = taste_zu_spieler(tasten, k0) s1 = taste_zu_spieler(tasten, k1) if s0 >= 0 and s1 >= 0 and s0 != s1: obj0 = taste_zu_objekt(tasten, k0) obj1 = taste_zu_objekt(tasten, k1) if s0 == 1: swap = obj1 obj1 = obj0 obj0 = swap print("{0:40}{1:40}".format(spieler[0], spieler[1])) print("{0:40}{1:40}".format("v", "v")) print("{0:40}{1:40}".format(objekte[obj0], objekte[obj1])) print("-" * 80) s = auswertung(obj0, obj1) if s >= 0: if s == 0: print_bild(bilder, obj0, 0) else: print_bild(bilder, obj1, 40) # Punktestand anpassen punkte[s] = punkte[s] + 1 ga = None if s == 0: ga = gewinn_aktion(obj0, obj1) else: ga = gewinn_aktion(obj1, obj0) print(">> {0} hat gewonnen, denn {1}".format(spieler[s], ga)) else: print(">> UNENTSCHIEDEN") print(" Punktestand:") print("{0:40}{1:40}".format(spieler[0] + " ({0})".format(punkte[0]), spieler[1] + " ({0})".format(punkte[1]))) else: print("!Ungültig!") def hole_spielernamen(): spieler0 = None spieler1 = None if len(sys.argv) == 3: spieler0 = sys.argv[1] spieler1 = sys.argv[2] else: print("Bitte Namen per Hand eintragen.") spieler0 = input("Spieler 1: ") spieler1 = input("Spieler 2: ") print("") return [ spieler0, spieler1 ] def lade_bilder(): bilder = [] with open('sp-data/stein.txt') as f: bilder.append(f.read()) with open('sp-data/papier.txt') as f: bilder.append(f.read()) with open('sp-data/schere.txt') as f: bilder.append(f.read()) return bilder def print_bild(bilder, obj, offset = 0): if offset == 0: print(bilder[obj]) else: bild = bilder[obj] zeilen = bild.split(os.linesep) for z in zeilen: print(" " * offset + z) def spieler_mit_punkte(spielername, punkte): return "{0} ({1})".format(spielername, punkte) class PunkteDatei: def __init__(self): self._dateiname = '_steinpapierschere.save' # Ein Dictionary, das alle Benutzer enthält, die bereits gespielt haben: # z. B. { 'Kurt': 10, 'Lea': 20 } self.punktestand_gesamt = { } def load(self): try: with open(self._dateiname, 'rb') as f: self.punktestand_gesamt = pickle.load(f) except FileNotFoundError: pass def save(self): with open(self._dateiname, 'wb') as f: pickle.dump(self.punktestand_gesamt, f, 0) ############################################################################### ### main ############################################################################### def main(): print(" ---------------------------------------") print(" Hallo zum Stein-Papier-Schere-Spiel ") print(" ---------------------------------------") print("") objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D' ], [ 'J', 'K', 'L' ] ] bilder = lade_bilder() spieler = hole_spielernamen() punkte = [ 0, 0 ] # Punkte-Datei laden p_datei = PunkteDatei() p_datei.load() # und Werte zuweisen, falls bereits vorhanden for i in range(2): if spieler[i] in p_datei.punktestand_gesamt: punkte[i] = p_datei.punktestand_gesamt[spieler[i]] print("{0:40}{1:40}".format("Spieler 1", "Spieler 2")) print("{0:40}{1:40}".format("---------", "---------")) print("{0:40}{1:40}".format(spieler_mit_punkte(spieler[0], punkte[0]), spieler_mit_punkte(spieler[1], punkte[1]))) print("") print(" Tasten:\n") for i in range(3): print("{0} = {1:36}{2} = {3:36}".format(tasten[0][i], objekte[i], tasten[1][i], objekte[i])) print("") print("Spielverlauf:") print(" 1. Jeder Spieler drückt eine seiner Tasten zur Vorbereitung.") print(" 2. Nochmal Vorbereitung.") print(" 3. Jeder Spieler drückt die Taste, mit der er seinen Gegenspieler herausfordert.") print("") ready(tasten) ready(tasten) fight(tasten, spieler, objekte, punkte, bilder) print("") # Punktestand speichern for i in range(2): if spieler[i] not in p_datei.punktestand_gesamt: p_datei.punktestand_gesamt[spieler[i]] = 0 p_datei.punktestand_gesamt[spieler[i]] = punkte[i] p_datei.save() if __name__ == "__main__": main()
Übung
-
Schau dir den Inhalt der Punktestand-Datei an und versuche, die Punktzahl eines Spielers manuell zu ändern.
11. Cheat
-
Einbau einer Spezialtaste, so dass eingeweihte Personen nicht verlieren können.
-
Das heißt unter anderem, eine Funktion zu schreiben, die zu einem Objekt das passende Gewinnobjekt auswählt.
-
#!/usr/bin/python3 """ Das Stein-Papier-Schere-Spiel """ import sys import os import pickle from getch import * ############################################################################### ### Funktionen ############################################################################### def taste_zu_spieler(tasten, k): if k.upper() in tasten[0]: return 0 elif k.upper() in tasten[1]: return 1 else: return -1 def taste_zu_objekt(tasten, k): k = k.upper() # Großbuchstabe if k in tasten[0]: return tasten[0].index(k) elif k in tasten[1]: return tasten[1].index(k) else: return -1 def gewinn_aktion(obj0, obj1): """ Liefert den Text wie obj0 über obj1 gewinnt. Wenn obj0 gegenüber obj1 verliert, wird "ungültig" geliefert """ if obj0 == 0 and obj1 == 2: return "Stein macht Schere stumpf." if obj0 == 1 and obj1 == 0: return "Papier umwickelt Stein." if obj0 == 2 and obj1 == 1: return "Schere zerschneidet Papier." return "ungültig" def auswertung(obj0, obj1): """ obj0 gehört zu spieler0. obj1 gehört zu spieler1. Liefert zurück, wer gewonnen hat (0 oder 1) oder -1 für unentschieden """ if obj0 == 0 and obj1 == 2 or obj0 == 1 and obj1 == 0 or obj0 == 2 and obj1 == 1: return 0 elif obj1 == 0 and obj0 == 2 or obj1 == 1 and obj0 == 0 or obj1 == 2 and obj0 == 1: return 1 else: return -1 def ready(tasten): print("Ready... ", end="") sys.stdout.flush() # damit die Ausgabe sofort erscheint k0 = getch() k1 = getch() s0 = taste_zu_spieler(tasten, k0) s1 = taste_zu_spieler(tasten, k1) if s0 >= 0 and s1 >= 0 and s0 != s1: print("OK\n") else: print("!Ungültig!") def fight(tasten, spieler, objekte, punkte, bilder): print("Go...") print("") k0 = getch() k1 = getch() s0 = taste_zu_spieler(tasten, k0) s1 = taste_zu_spieler(tasten, k1) if s0 >= 0 and s1 >= 0 and s0 != s1: obj = [ None, None ] obj[0] = taste_zu_objekt(tasten, k0) obj[1] = taste_zu_objekt(tasten, k1) if s0 == 1: swap = obj[1] obj[1] = obj[0] obj[0] = swap # obj0 gehört nun zu spieler0 # Cheat: other = [ obj[1], obj[0] ] for i in range(2): if obj[i] == 3: # Cheat-Taste if other[i] == 0: obj[i] = 1 elif other[i] == 1: obj[i] = 2 elif other[i] == 2: obj[i] = 0 else: obj[i] = 0 # beide haben geschummelt => unentschieden print("{0:40}{1:40}".format(spieler[0], spieler[1])) print("{0:40}{1:40}".format(" |", " |")) print("{0:40}{1:40}".format(" v", " v")) print("{0:40}{1:40}".format(objekte[obj[0]], objekte[obj[1]])) print("-" * 80) s = auswertung(obj[0], obj[1]) if s >= 0: if s == 0: print_bild(bilder, obj[0], 0) else: print_bild(bilder, obj[1], 40) # Punktestand anpassen punkte[s] = punkte[s] + 1 ga = None if s == 0: ga = gewinn_aktion(obj[0], obj[1]) else: ga = gewinn_aktion(obj[1], obj[0]) print(">> {0} hat gewonnen, denn {1}".format(spieler[s], ga)) else: print(">> UNENTSCHIEDEN") print(" Punktestand:") print("{0:40}{1:40}".format(spieler[0] + " ({0})".format(punkte[0]), spieler[1] + " ({0})".format(punkte[1]))) else: print("!Ungültig!") def hole_spielernamen(): spieler0 = None spieler1 = None if len(sys.argv) == 3: spieler0 = sys.argv[1] spieler1 = sys.argv[2] else: print("Bitte Namen per Hand eintragen.") spieler0 = input("Spieler 1: ") spieler1 = input("Spieler 2: ") print("") return [ spieler0, spieler1 ] def lade_bilder(): bilder = [] with open('sp-data/stein.txt') as f: bilder.append(f.read()) with open('sp-data/papier.txt') as f: bilder.append(f.read()) with open('sp-data/schere.txt') as f: bilder.append(f.read()) return bilder def print_bild(bilder, obj, offset = 0): if offset == 0: print(bilder[obj]) else: bild = bilder[obj] zeilen = bild.split(os.linesep) for z in zeilen: print(" " * offset + z) def spieler_mit_punkte(spielername, punkte): return "{0} ({1})".format(spielername, punkte) class PunkteDatei: def __init__(self): self._dateiname = '_steinpapierschere.save' # Ein Dictionary, das alle Benutzer enthält, die bereits gespielt haben: # z. B. { 'Kurt': 10, 'Lea': 20 } self.punktestand_gesamt = { } def load(self): try: with open(self._dateiname, 'rb') as f: self.punktestand_gesamt = pickle.load(f) except FileNotFoundError: pass def save(self): with open(self._dateiname, 'wb') as f: pickle.dump(self.punktestand_gesamt, f, 0) ############################################################################### ### main ############################################################################### def main(): print(" ---------------------------------------") print(" Hallo zum Stein-Papier-Schere-Spiel ") print(" ---------------------------------------") print("") objekte = [ "Stein", "Papier", "Schere" ] # erste Zeile für Spieler 1 und zweite Zeile für Spieler 2 tasten = [ [ 'A', 'S', 'D', 'W' ], [ 'J', 'K', 'L', 'I' ] ] bilder = lade_bilder() spieler = hole_spielernamen() punkte = [ 0, 0 ] # Punkte-Datei laden p_datei = PunkteDatei() p_datei.load() # und Werte zuweisen, falls bereits vorhanden for i in range(2): if spieler[i] in p_datei.punktestand_gesamt: punkte[i] = p_datei.punktestand_gesamt[spieler[i]] print("{0:40}{1:40}".format("Spieler 1", "Spieler 2")) print("{0:40}{1:40}".format("---------", "---------")) print("{0:40}{1:40}".format(spieler_mit_punkte(spieler[0], punkte[0]), spieler_mit_punkte(spieler[1], punkte[1]))) print("") print(" Tasten:\n") for i in range(3): print("{0} = {1:36}{2} = {3:36}".format(tasten[0][i], objekte[i], tasten[1][i], objekte[i])) print("") print("Spielverlauf:") print(" 1. Jeder Spieler drückt eine seiner Tasten zur Vorbereitung.") print(" 2. Nochmal Vorbereitung.") print(" 3. Jeder Spieler drückt die Taste, mit der er seinen Gegenspieler herausfordert.") print("") ready(tasten) ready(tasten) fight(tasten, spieler, objekte, punkte, bilder) print("") # Punktestand speichern for i in range(2): if spieler[i] not in p_datei.punktestand_gesamt: p_datei.punktestand_gesamt[spieler[i]] = 0 p_datei.punktestand_gesamt[spieler[i]] = punkte[i] p_datei.save() if __name__ == "__main__": main()
Lerneffekt: Traue keinem Programm, dessen Quellcode nicht eingesehen werden kann.
12. Erweiterung
Erweitere das Spiel, so dass man (Bonus: als Option) "Papier, Stein, Schere, Echse, Spock" spielen kann.