Hallo Leute,
es geht um ein einfaches Schere,Stein,Papier Spiel dessen Code ihr hier findet.
http://www.python-forum.de/pastebin.php?mode=view&s=193
Ich bin leider ein blutiger Programmieranfänger und freue mich daher über jeden Tipp
der den Code eleganter und das Programm stabiler macht.
Gültige Eingaben sind r,p oder s.
derrick
Einfaches Schere,Stein,Papier Spiel
Da könnte man einiges zu sagen. Ich beschränke mich mal auf den Hinweis, dass return eine Anweisung und keine Funktion ist und infolgedessen ohne Klammern auskommt. Die Ermittlung des Gewinnners lässt sich erheblich kürzer fassen, etwa so:
Code: Alles auswählen
def winner(comp,user):
if comp == user:
return "draw"
elif user+comp in ["rs","pr","sp"]:
return "user"
return "comp"
Na dann fangen wir doch genau da an. Du hast die Eingabe sehr schön in die Funktion get_userinput gepackt. Es wäre sicher sinnvoll, in dieser Funktion dann auch zu überprüfen, ob ein gültiger Buchstabe eingegeben wurde. Ich habe ein "a" eingegeben und das Programm hat mich nicht zur Neueingabe aufgefordert und hat auch beim Vergleich nicht gemerkt, dass der Wert "a" eigentlich nicht vorkommen darf. Statt dessen hatte ich das Spiel verloren - und das wo "a" (Atom bomb) ja nun wirklich eigentlich alles schlägt.derrick hat geschrieben:es geht um ein einfaches Schere,Stein,Papier Spiel dessen Code ihr hier findet.
http://www.python-forum.de/pastebin.php?mode=view&s=193
Ich bin leider ein blutiger Programmieranfänger und freue mich daher über jeden Tipp
der den Code eleganter und das Programm stabiler macht.
Gültige Eingaben sind r,p oder s.
In compare_input sehe ich sehr viele Aufrufe von show_result(). Den könnte man ein einziges Mal am Ende ausführen. Eigentlich würde ich das Ergebnis überhaupt nicht aus der Vergleichsfunktion heraus anzeigen.
show_result lügt - zumindest vom Namen der Funktion her. Es zeigt nicht nur Resultate sondern rechnet auch noch. Es rechnet vor allem anhand eines Textes, der in erster Linie für die Ausgabe relevant ist. Eine Übersetzung der Ausgabetexte in eine andere Sprache oder auch nur die minimale Veränderung eines in compare_input definierten Ausgabetextes würde plötzlich falsche Ergebnisse erzeugen. Hier muss eine andere Lösung her und bei der Gelegenheit sollte man auch direkt die globals entsorgen.
Allgemein noch zum Code: Bei Rückgaben mit return solltest du die folgenden Klammern weglassen.
Mal auf die Schnelle ein paar kleine Veränderungen: http://www.python-forum.de/pastebin.php?mode=view&s=194. Man muss sich immer so zügeln, sonst entsteht gleich wieder ein Moloch der dann richtig ausgefuchst ist - und mit dem ein Anfänger nichts anfangen kann.
Mit dieser Variante ist es auf jeden Fall leichter möglich "Stein, Schere, Papier" durch "Stein, Schere, Papier, Spock, Echse" zu erweitern.
Mit dieser Variante ist es auf jeden Fall leichter möglich "Stein, Schere, Papier" durch "Stein, Schere, Papier, Spock, Echse" zu erweitern.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Man könnte auch noch einen "Computer vs. Computer" / "Mensch vs. Mensch"-Modus einbauen, indem man die Input-Funktionen übergibt bzw. den Code dafür auslegt, dass die Funktionen übergeben werden. Ich hatte das vor olims Zeiten mal in einem kleinen Script für das Ziegenproblem angewendet (Code ist nicht PEP8 konform!).
Dieses Spielchen ist nebenbei auch immer ein schönes Beispiel für eine nicht transitive Ordnung - schade, dass viele Lehrkräfte so etwas anschauliches nicht als Beispiel in diesem Kontext bringen. Ist bei mir zumindest nie vorgekommen
Dieses Spielchen ist nebenbei auch immer ein schönes Beispiel für eine nicht transitive Ordnung - schade, dass viele Lehrkräfte so etwas anschauliches nicht als Beispiel in diesem Kontext bringen. Ist bei mir zumindest nie vorgekommen

encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
- pillmuncher
- User
- Beiträge: 1530
- Registriert: Samstag 21. März 2009, 22:59
- Wohnort: Pfaffenwinkel
Du meinst sowas, oder? Den etwas fortgeschritteneren kann man damit immerhin zeigen, dass man oft auch ganz ohne if-Statement auskommen kann./me hat geschrieben:Man muss sich immer so zügeln, sonst entsteht gleich wieder ein Moloch der dann richtig ausgefuchst ist - und mit dem ein Anfänger nichts anfangen kann.
Gruß,
Mick.
In specifications, Murphy's Law supersedes Ohm's.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Nicepillmuncher hat geschrieben:Du meinst sowas, oder? Den etwas fortgeschritteneren kann man damit immerhin zeigen, dass man oft auch ganz ohne if-Statement auskommen kann.

So, ich denke der Thread hat das Potenzial für Lösungen in verschiedenen Sprachen! Wer zeigt die erste Scheme / Lisp-Lösung?

encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Danke euch für euren Code!
Hab mir jetzt einiges abgeschaut und die Eingaben werden auch geprüft.
Das mit der Matrix ist genial, habe es aber mal mit numerix Vorschlag gemacht,
auch wenn das dann schwerer zu erweitern ist.
Also hier ist der neue Code(http://www.python-forum.de/pastebin.php?mode=view&s=196).
Was haltet ihr davon?
Hab mir jetzt einiges abgeschaut und die Eingaben werden auch geprüft.
Das mit der Matrix ist genial, habe es aber mal mit numerix Vorschlag gemacht,
auch wenn das dann schwerer zu erweitern ist.
Also hier ist der neue Code(http://www.python-forum.de/pastebin.php?mode=view&s=196).
Was haltet ihr davon?
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Also mal ein paar Anmerkungen:
- In Zeile 11 hast Du ein Klammerpaar zu viel
- `return` ist in Python ein Statement und keine Funktion; also solltest Du das nicht klammern (Zeilen 12 & 17)
- Operatoren sollten immer durch Leerzeichen getrennt werden (außer innerhalb von Funktionsaufrufen):
- die Funktion `get_computerinput` kann man einfacher fomulieren:
Das Binden an eine lokale Variable ist hier unnötig, da der Name nur für das return-Statement aufgegriffen wird. Faustregel ist dabei (imho), dass man Objekte nur dann an Namen bindet, wenn man diesen Namen auch wirklich benötigt.
- in der Funktion `get_userinput` fände ich eine Fehlermeldung gut, wenn der Benutzer ein falsches Zeichen eingibt.
- Du verwendest `allowed_input` nicht konsequent (`get_computerinput`); damit ist der Vorteil einer globalen Definition quasi dahin
- in `show_winner` empfinde ich die Leerzeilen als störend.
- Shebang und Kodierungsangabe fehlen - muss natürlich nicht sein, aber bei einem "kompletten" Script gehört das imho dazu.
- Den Code ab Zeile 46 würde ich von Modulebene wegnehmen und in eine Funktion packen. Diese kann man dann über eine `main`-Funktion aufrufen.
Darüber hinaus würde ich als nächsten Schritt weg vom statischen Mensch vs. Computer und die Funktionen aus der neuen `main`-Funktion an die `main_loop`-Funktion übergeben. Damit hast Du einfach zwei Funktionen, die die Entscheidung eines Spielers ermitteln - ob das nun ein Mensch ist, oder der PC oder eben zwei Menschen ist ja für das Spiel (also die Auswertung, das Scoring usw) egal.
Falls Du das noch nicht gesehen hast, verweise ich noch mal auf meinen obigen Post und das dort verlinkte Script. Du kannst Funktionen - wie jedes Objekt in Python - an einen Namen binden oder als Parameter übergeben.
Du brauchst also keine komplizierte Logik, um zu prüfen, welche Funktion Du für einen Spieler aufrufen musst, sondern übergibst einfach die gewünschte(n) Funktion(en) an Deine Spiellogik-Funktion und gut ist.
Die Namen `user_input` und `computer_input` passen dann natürlich nicht mehr; könnte man dann neutral `user_a` und `user_b` nennen¹ oder in eine Liste / Dict verpacken. Da Du ja bereits ein `score`-Dict hast, könnte man das um die Funktion erweitern? Ich würde dann noch `argparse` nutzen, um den `winscore` optional übergeben zu können und vor allem die Funktionen, welche die beiden Spielereingaben bestimmen.
- In Zeile 11 hast Du ein Klammerpaar zu viel
- `return` ist in Python ein Statement und keine Funktion; also solltest Du das nicht klammern (Zeilen 12 & 17)
- Operatoren sollten immer durch Leerzeichen getrennt werden (außer innerhalb von Funktionsaufrufen):
Code: Alles auswählen
# falsch
score['human']+=1
# richtig
score['human'] += 1
Code: Alles auswählen
def get_computer_input():
return random.choice('rps')
- in der Funktion `get_userinput` fände ich eine Fehlermeldung gut, wenn der Benutzer ein falsches Zeichen eingibt.
- Du verwendest `allowed_input` nicht konsequent (`get_computerinput`); damit ist der Vorteil einer globalen Definition quasi dahin

- in `show_winner` empfinde ich die Leerzeilen als störend.
- Shebang und Kodierungsangabe fehlen - muss natürlich nicht sein, aber bei einem "kompletten" Script gehört das imho dazu.
- Den Code ab Zeile 46 würde ich von Modulebene wegnehmen und in eine Funktion packen. Diese kann man dann über eine `main`-Funktion aufrufen.
Code: Alles auswählen
def main_loop():
win_score = get_winscore()
# ...
def main():
# sys.args parsen o.ä.
main_loop()
if __name__ == "__main__":
main()
Falls Du das noch nicht gesehen hast, verweise ich noch mal auf meinen obigen Post und das dort verlinkte Script. Du kannst Funktionen - wie jedes Objekt in Python - an einen Namen binden oder als Parameter übergeben.
Code: Alles auswählen
In [11]: def foo():
....: print "Hallo"
....:
....:
In [12]: def bar():
....: print "Ciao"
....:
....:
In [13]: def logic(func):
....: func()
....:
....:
In [14]: logic(foo)
Hallo
In [15]: logic(bar)
Ciao
In [16]: f = foo
In [17]: f()
Hallo
Die Namen `user_input` und `computer_input` passen dann natürlich nicht mehr; könnte man dann neutral `user_a` und `user_b` nennen¹ oder in eine Liste / Dict verpacken. Da Du ja bereits ein `score`-Dict hast, könnte man das um die Funktion erweitern? Ich würde dann noch `argparse` nutzen, um den `winscore` optional übergeben zu können und vor allem die Funktionen, welche die beiden Spielereingaben bestimmen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert