Abend Leute,
ich habe ein Hangmanspiel geschrieben als Lösung für diese Aufgabe(Bitte anschauen damit ihr wisst was für eine Formatierung verlangt wird)http://openbookproject.net/pybiblio/pra ... angman.php
Allerdings bin ich bei der Verwaltung der Zeichenfolge des zu suchenden Worts auf meine
Grenzen gestoßen, was den Code unnötig unelegant macht. Ich habe mich extra bemüht den Code ausführlich zu dokumentieren und würde mich daher freuen wenn sich jemand die analyse_guess() und end_round() Methoden
ansehen würde und mir hilft eine bessere Lösung zu finden.
Hier der Code: http://www.python-forum.de/pastebin.php?mode=view&s=215
Solltet ihr das Programm testen wollen muss eine HangmanWords.txt im richtigen Verzeichniss verfügbar sein.
Eingabenprüfung ist noch nicht implementiert also bitte an die Inputaufforderung halten !
Vielen Dank für eure Mühe
derrick
Hangman
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Und eine leere Datei diesen Namens reicht aus?derrick hat geschrieben: Solltet ihr das Programm testen wollen muss eine HangmanWords.txt im richtigen Verzeichniss verfügbar sein.
Will sagen: Wieso stellst Du die nicht zum Testen bereit. Alternativ baust Du ein default-Wort ein oder eine Liste von einigen Wörtern. Das wäre für potenzielle Tester angenehmer und macht einen besseren Eindruck
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
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Ohne es getestet zu haben und nur auf die Schneller:
- Ich glaube Du brauchst da keine Klassen, oder wenn eine bessere Struktur. Player ist zumindest so überflüssig
- Binde nicht verschiedene Datentypen nacheinander an denselben Namen:
Zumal Du Dir die erste Zeile auch sparen könntest
(über den Namen reden wir mal besser nicht )
- Boolesche Zustände würde ich mit `True` und `False` abbilden, nicht mit "0" und "1" (self.go_on)
- Shebang und Kodierungsangabe fehlen
Du könntest mal die SuFu benutzen; iirc hatten wir schon zig Hangmans hier mit teilweise guten Ansätzen, die eigentliche Logik zu implementieren.
- Ich glaube Du brauchst da keine Klassen, oder wenn eine bessere Struktur. Player ist zumindest so überflüssig
- Binde nicht verschiedene Datentypen nacheinander an denselben Namen:
Code: Alles auswählen
length_word = random.choice(length_list)
length_word = [char for char in length_word]
Code: Alles auswählen
length_word = [char for char in random.choice(length_list)]
- Boolesche Zustände würde ich mit `True` und `False` abbilden, nicht mit "0" und "1" (self.go_on)
- Shebang und Kodierungsangabe fehlen
Du könntest mal die SuFu benutzen; iirc hatten wir schon zig Hangmans hier mit teilweise guten Ansätzen, die eigentliche Logik zu implementieren.
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
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
So, hab mir mal was überlegt:
Die Idee dahinter ist es, sich die vorkommenden Buchstaben zusammen mit ihren Indizes in einem dict zu merken. Damit kommt man schnell darauf, ob ein Buchstabe im Wort enthalten ist und zudem an die Positionen.
Zudem legt man sich eine Liste an, die der Länge des ursprünglichen Wortes umfasst und aus Platzhaltern besteht.
Bei einer Tippabgabe kann man nun die Positionen dieser Liste leicht gegen den richtigen Tipp ersetzen.
Damit kann man zudem leicht die minimal benötigten Rateversuche bestimmen (Anzahl der Schlüssel in `indexes`).
Code: Alles auswählen
In [1]: secret = "Programmiersprache"
In [3]: from collections import defaultdict
In [4]: indexes = defaultdict(list)
In [6]: for index, char in enumerate(secret.lower()):
...: indexes[char].append(index)
...:
...:
In [7]: indexes
Out[7]: defaultdict(<type 'list'>, {'a': [5, 14], 'c': [15], 'e': [9, 17], 'g':
[3], 'i': [8], 'h': [16], 'm': [6, 7], 'o': [2], 'p': [0, 12], 's': [11], 'r': [
1, 4, 10, 13]})
In [8]: guessed_chars = ["_" for _ in xrange(len(secret))]
In [9]: guess = "e"
In [10]: indexes[guess]
Out[10]: [9, 17]
In [11]: for index in indexes[guess]:
....: guessed_chars[index] = guess
....:
....:
In [12]: print " ".join(guessed_chars)
-------> print(" ".join(guessed_chars))
_ _ _ _ _ _ _ _ _ e _ _ _ _ _ _ _ e
Zudem legt man sich eine Liste an, die der Länge des ursprünglichen Wortes umfasst und aus Platzhaltern besteht.
Bei einer Tippabgabe kann man nun die Positionen dieser Liste leicht gegen den richtigen Tipp ersetzen.
Damit kann man zudem leicht die minimal benötigten Rateversuche bestimmen (Anzahl der Schlüssel in `indexes`).
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 für den Ansatz Hyperion ist echt um einiges schöner und das gesuchte Wort wird dabei nicht zerstört.
Ich habe aber noch zusätzlich eine string-Version des gesuchten Worts speichern müssen um die korrekte Platzhalteranzahl mit len() zu ermitteln und um zu testen ob der User bereits alle Buchstaben eraten hat.Lässt sich das irgendwie umgehen?
Eine andere Frage die ich noch hätte: Wir überprüft man möglichst einfach ob ein input ein Buchstabe ist,mache das aktuell über eine liste aller Buchstaben des (englischen) Alphabets.
Hier der neue Code: http://www.python-forum.de/pastebin.php?mode=view&s=216
Hier die HangmanWords.txt : http://www.python-forum.de/pastebin.php?mode=view&s=217
Grüße
derrick
Ich habe aber noch zusätzlich eine string-Version des gesuchten Worts speichern müssen um die korrekte Platzhalteranzahl mit len() zu ermitteln und um zu testen ob der User bereits alle Buchstaben eraten hat.Lässt sich das irgendwie umgehen?
Eine andere Frage die ich noch hätte: Wir überprüft man möglichst einfach ob ein input ein Buchstabe ist,mache das aktuell über eine liste aller Buchstaben des (englischen) Alphabets.
Hier der neue Code: http://www.python-forum.de/pastebin.php?mode=view&s=216
Hier die HangmanWords.txt : http://www.python-forum.de/pastebin.php?mode=view&s=217
Grüße
derrick
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Da gibt es einige Möglichkeiten:derrick hat geschrieben: Ich habe aber noch zusätzlich eine string-Version des gesuchten Worts speichern müssen um die korrekte Platzhalteranzahl mit len() zu ermitteln und um zu testen ob der User bereits alle Buchstaben eraten hat.Lässt sich das irgendwie umgehen?
Du könntest einen Zähler einbauen, der zu Beginn der Länge des Wortes entspricht. Anschließend kannst Du bei jeder Ersetzung reduzieren. Ist er 0 ist das Wort komplett erraten.
Oder aber Du berechnest eben die noch verbliebenen Stellen im Wort immer neu. Da die Wörter ja recht kurz sind, würde ich das trotz schlechterer Effizienz evtl. vorziehen, da man sich den Zähler spart:
Code: Alles auswählen
len((_ for _ in guessed_chars if _ == "_"))
Um dann ggf. eine Meldung auszugeben, dass ein abgegebener Buchstabe schon erraten wurde, könnte man diese in einer separaten Liste führen. (`guessed_chars` wäre da ein passender Name -> also die Liste mit Platzhaltern sinnvoller benennen )
Ich denke letzteres ist am elegantesten.
Guck mal ins `string`-Modul. Da gibts vorgefertigte "Konstanten" mit denen Du per "x iny"-Idiom das leicht testen kannst.Eine andere Frage die ich noch hätte: Wir überprüft man möglichst einfach ob ein input ein Buchstabe ist,mache das aktuell über eine liste aller Buchstaben des (englischen) Alphabets.
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
derrick hat geschrieben:Wir überprüft man möglichst einfach ob ein input ein Buchstabe ist,...
Code: Alles auswählen
In [27]: 'a'.isalpha()
Out[27]: True
In [28]: '1'.isdigit()
Out[28]: True
In [29]: 'a1'.isalnum()
Out[29]: True
In [30]: ' '.isspace()
Out[30]: True
In [31]: 'A'.isupper()
Out[31]: True
In [32]: 'a'.islower()
Out[32]: True
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
Danke euch beiden für die Vorschläge hab sie nun eingebaut.
@Hyperion: Ich habe mich für entschieden wobei
die inneren runden Klammern eckig sein müssen
Viele Grüße
derrick
@Hyperion: Ich habe mich für
Code: Alles auswählen
len((_ for _ in guessed_chars if _ == "_"))
die inneren runden Klammern eckig sein müssen
Viele Grüße
derrick
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Ach Mist... hast Recht. Logisch eigentlich, dass ein Generator-Objekt nicht mit len() funzen kann; es kann ja unendlich Werte zurückliefern.derrick hat geschrieben: die inneren runden Klammern eckig sein müssen
Wieso hast Du nicht den dritten Vorschlag gewählt? Habe ich da was in der Logik übersehen?
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
Bleibt nur die Frage, wie man Umlaute als Buchstaben erkennen kann:
Ab python3 funktionierts:
Code: Alles auswählen
In [48]: 'ü'.isalpha()
Out[48]: False
In [49]: u'ü'.isalpha()
Out[49]: False
In [50]: from __future__ import unicode_literals
In [51]: 'ü'.isalpha()
Out[51]: False
Code: Alles auswählen
>>> 'ü'.isalpha()
True
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
sma hatte da mal einen Vorschlag via RegExp gebracht: Link.mutetella hat geschrieben:Bleibt nur die Frage, wie man Umlaute als Buchstaben erkennen kann:
Ansonsten eben: Python3 benutzen
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
Deshalb hab ich eine englische Wortliste(keine Umlaute) und benutz Python3
@Hyperion: Dein 3. Vorschlag wäre auch möglich aber iwie gefällt mir die Vorstellung nicht
etwas aus diesem dict zu löschen Vor Allem da Ram und Rechenleistung in rauen Mengen vorhanden
sind
Grüße
derrick
@Hyperion: Dein 3. Vorschlag wäre auch möglich aber iwie gefällt mir die Vorstellung nicht
etwas aus diesem dict zu löschen Vor Allem da Ram und Rechenleistung in rauen Mengen vorhanden
sind
Grüße
derrick
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Naja, das ist ja ein spezielles Datenobjekt, welches nur temporären Bestand hat. Du änderst ja nach jedem (erfolgreichem) Tippzug auch die Liste mit den Platzhaltern. Letztlich bildest Du ja einen Zustand ab; dieser ist nun mal dynamisch. Mir fällt spontan da nichts ein, wieso man erratene Buchstaben da nicht rausnehmen könnte. Vorteil wäre, dass Du recht einfach rausfinden ohne Kalkulation rausfinden kannst, ob ein Wort eraten wurde.derrick hat geschrieben: @Hyperion: Dein 3. Vorschlag wäre auch möglich aber iwie gefällt mir die Vorstellung nicht etwas aus diesem dict zu löschen
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
Grundsätzlich hast du mich überzeugt aber,
Wenn man dann mit anschliesen will muss man halt vorher überprüfen ob
guess überhaupt einen bzw. mehrere Indizes hat also vorhanden ist. Sonst gibts nen Key-Error.
Grüße
derrick
Code: Alles auswählen
for index in self.searched_word[guess]:
self.correct_guesses[index] = guess
Code: Alles auswählen
self.searched_word.pop(guess)
guess überhaupt einen bzw. mehrere Indizes hat also vorhanden ist. Sonst gibts nen Key-Error.
Grüße
derrick
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Naja, das ist ja nicht so wild. Damit kannst Du Dir ja dann sparen zu testen, ob der Test schon abgegeben wurde - da kommt also kein neuer Test hinzu. Ich würde da evtl. auch mit try...except arbeiten.derrick hat geschrieben:Grundsätzlich hast du mich überzeugt aber,
Wenn man dann mitCode: Alles auswählen
for index in self.searched_word[guess]: self.correct_guesses[index] = guess
anschliesen will muss man halt vorher überprüfen obCode: Alles auswählen
self.searched_word.pop(guess)
guess überhaupt einen bzw. mehrere Indizes hat also vorhanden ist. Sonst gibts nen Key-Error.
Grüße
derrick
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
@mutetella: Das ist ein Fehler in IPython. Im Standardinterpeter oder in Modulen funktioniert es:
Natürlich nur mit unicode-Objekten.
Code: Alles auswählen
>>> u'ü'.isalpha()
True
@lunar:
Danke für den Hinweis. Bin schon mal über den Bug gestolpert, hab' ich doch glatt vergessen...
Danke für den Hinweis. Bin schon mal über den Bug gestolpert, hab' ich doch glatt vergessen...
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )