zahlenratespiel

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
wildflower
User
Beiträge: 6
Registriert: Montag 1. Juni 2009, 11:06

Hallo. Habe mal als erstes Programm ein Zahlenratespiel geschrieben. Nur irgendwie kriege ich das mit dem "pickle" nicht so richtig hin, und ich finde den Fehler nicht. Kann mir jemand helfen?

Code: Alles auswählen

#!/usr/bin/python

import random
import pickle

def zufall():
    spiel = 1
    menu = 0
    x = 0
    while spiel == 1:
        versuche = 0
        counter = 0
        # Spiel starten, beenden, oder Highscore anzeigen
        print "\nZahlen raten"
        print "_-_-_-_-_-_-_-"
        print "(1) Neues Spiel"
        print "(2) Highscores"
        print "(3) Beenden"
        menu = int(raw_input(" > "))
        # Nun wird der Schwierigkeitsgrad gewaehlt
        if menu == 1:
            print "\nSchwierigkeitsgrad waehlen:"
            print "_-_-_-_-_-_-_-_-_-_-_-_-_-_-"
            print "(1) leicht"
            print "(2) mittel"
            print "(3) schwer"
            schwgrad = int(raw_input(" > "))
            if schwgrad == 1:
                x = random.randint(1,100)
                versuche = 10
            elif schwgrad == 2:
                x = random.randint(1,1000)
                versuche = 11
            elif schwgrad == 3:
                x = random.randint(1,10000)
                versuche = 11
            else:
                print "\nDieser Schwierigkeitsgrad existiert nicht."
                continue
            # Hier wird die Eingabe ausgewertet. Solange man weniger Versuche hat,
            # darf man weiterraten
            while versuche != 0:
                guess = int(raw_input("Bitte Zahl eingeben: "))
                if guess < x:
                    print "Zu niedrig."
                    counter += 1
                    versuche -= 1
                elif guess > x:
                    print "Zu hoch."
                    counter += 1
                    versuche -= 1
                # Wenn richtig geraten, dann wird man per pickle in die
                # Highscoreliste eingetragen. 
                elif guess == x:
                    counter += 1
                    versuche -= 1
                    print "Super, nach %i Versuchen geschafft!" % counter
                    name = raw_input("\nBitte Name eingeben: ")
                    highscore = {name : counter}
                    f = open("highscore.txt", "a")
                    pickle.dump(highscore, f)
                    f.close()
                    print "Noch einmal versuchen?"
                    spiel = int(raw_input("(1) Ja\n(2) Nein\n> "))
                    if spiel == 2:
                        print "Spiel beendet!"
                        break
                    break
                if versuche == 0:
                    print "Leider nicht geschafft!"
                    print "Noch einmal versuchen?"
                    spiel = int(raw_input("(1) Ja\n(2) Nein\n> "))
                    if spiel == 2:
                        print "Spiel beendet!"
                        break
                    
        # Highscores laden und anzeigen            
        elif menu == 2:
            l = open("highscore.txt")
            data = pickle.load(l)
            print data
            
        # Spiel beenden   
        elif menu == 3:
            print "\nSpiel wurde beendet."
            break
        
zufall()
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Jeez, das ist ja ein unglaublicher Wust. Den solltest du erstmal aufräumen und dir abgewöhnen Spaghetticode zu schreiben. Ich sehe in deiner Funktion mindestens 4 weitere.

Was genau ist denn das Problem (am besten mit Fehlermeldung)? Hast du die Doku schon gelesen? Daneben sollte man Pickles immer binär schreiben und lesen ("b" an den Modus anhängen -> "ab", "rb").
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Du solltest deinen highscore entweder:
- als liste picklen (kannst du sortieren und. z.B. auf die besten 10 beschränken)
- komplett laden: zu jedem dump() gehört auch ein load()
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

b.esser-wisser hat geschrieben:- komplett laden: zu jedem dump() gehört auch ein load()
Zur Erklärung: In Zeile 60 legst du immer ein neues Highscore-Dictionary an, ohne die Werte des Alten zu laden.
Wenn du ein Dictionary benutzen willst, kannst du auch auf ``shelve`` ausweichen. Das nimmt dir den Verwaltungsaufwand ab, denn du mit ``pickle`` hast.
wildflower
User
Beiträge: 6
Registriert: Montag 1. Juni 2009, 11:06

so, ich habs jetzt mal ein bisschen überarbeitet und mehrere funktionen daraus gemacht. ich hoffe, man kennt sich jetzt etwas besser aus :).
muss ich jetzt die variablen guess, counter, versuche usw global anlegen?

Code: Alles auswählen

#!/usr/bin/python

import random
import pickle

# Hier soll der Schwierigkeitsgrad gewaehlt werden
def schwierigk():
    print "\nSchwierigkeitsgrad waehlen:"
    print "_-_-_-_-_-_-_-_-_-_-_-_-_-_-"
    print "(1) leicht"
    print "(2) mittel"
    print "(3) schwer"
    schwgrad = int(raw_input(" > "))
    if schwgrad == 1:
        x = random.randint(1,100)
        versuche = 10
    elif schwgrad == 2:
        x = random.randint(1,1000)
        versuche = 11
    elif schwgrad == 3:
        x = random.randint(1,10000)
        versuche = 11
    else:
        print "\nDieser Schwierigkeitsgrad existiert nicht."

# Wenn richtig geraten, dann soll die Anzahl der Versuche in eine
# highscore.txt geschrieben werden
def richtig():
    if guess == x:
        counter += 1
        versuche -= 1
        print "Super, nach %i Versuchen geschafft!" % counter
        name = raw_input("\nBitte Name eingeben: ")
        high = "%s                    %i" % (name, counter)
        f = open("highscore.txt", "ab")
        score = []
        score = pickle.load("highscore.txt")
        score.append = high
        highscore = score.sort()
        pickle.dump(highscore, f)
        f.close()

def falsch():
    while versuche != 0:
        guess = int(raw_input("Bitte Zahl eingeben: "))
        if guess < x:
            print "Zu niedrig."
            counter += 1
            versuche -= 1
        elif guess > x:
            print "Zu hoch."
            counter += 1
            versuche -= 1

# Wahl, das Spiel noch einmal zu spielen
def nochmal():
    print "Noch einmal versuchen?"
    spiel = int(raw_input("(1) Ja\n(2) Nein\n> "))
    if spiel == 2:
        print "Spiel beendet!"

def zufall():
    spiel = 1
    menu = 0
    x = 0
    while spiel == 1:
        versuche = 0
        counter = 0
        # Spiel starten, beenden, oder Highscore anzeigen
        print "\nZahlen raten"
        print "_-_-_-_-_-_-_-"
        print "(1) Neues Spiel"
        print "(2) Highscores"
        print "(3) Beenden"
        menu = int(raw_input(" > "))
        # Nun wird der Schwierigkeitsgrad gewaehlt
        if menu == 1:
            schwierigk()
            falsch()
            richtig()
            nochmal()
            if versuche == 0:
                print "Leider nicht geschafft!"
                nochmal()
                    
        # Highscores laden und anzeigen            
        elif menu == 2:
            l = open("highscore.txt")
            data = pickle.load(l)
            print data
            
        # Spiel beenden   
        elif menu == 3:
            print "\nSpiel wurde beendet."
            break
        
zufall()
BlackJack

Nein, nichts global machen. Vergiss am besten, dass es ``global`` überhaupt gibt. Werte sollten Funktionen als Argumente betreten und als Rückgabewerte verlassen.

Die Aufteilung ist auch nicht so gelungen, weil es eher aussieht wie Programmblöcke, denen Namen gegeben worden sind, damit man sie "anspringen" kann und nicht wie Funktionen.

Funktionen sollten Namen haben, die ihre Tätigkeit ausdrücken, und auf Abkürzungen sollte man möglichst auch verzichten, es sei denn die sind wirklich *sehr* geläufig.

Die `schwierigk()`-Funktion sollte zum Beispiel ein Tupel mit der zu ratenden Zahl und der Anzahl der maximalen Versuche zurückgeben. Und `erfrage_schwierigkeitsgrad()` oder so ähnlich heissen. Die Fehlerbehandlung muss natürlich auch in der Funktion erfolgen. Wenn da vom Benutzer etwas falsches eingegeben wird, liegt es in der Verantwortung dieser Funktion, solange zu fragen, bis etwas sinnvolles zurückgegeben werden kann.

Teilweise sollte man auch anders Aufteilen. Zum Beispiel ist das laden und speichern der Bestenliste eine Aufgabe, die prima jeweils in eine Funktion abstrahiert werden kann.
Pascal
User
Beiträge: 271
Registriert: Samstag 4. April 2009, 22:18

Einige Dinge die mir aufgefallen sind:

1.Immer wenn du den counter um 1 hochzählst, zählst du versuche um eins runter. Die könnte man eigentlich ganz gut miteinander verknüpfen.


2. "menu = int(raw_input(" > "))" ?? Dann kann man auch gleich input nehmen. Allerdings würde ich vorschlagen das ganze über raw_input zu machen und dann abfragen: if menu == '1': an stelle von == 1.

3. Ich halte die Prozeduren nicht gerade für sinnvoll gewählt. (allerding ist das eher Ansichtssache) Edit: und scheinbar ist BlackJack der gleichen Meinung ;)

4. Den Highscore kann man schön leicht manipulieren :lol:
(nicht als txt speicher)
Hierzu mal ein Bsp.:

Code: Alles auswählen

mydict = {'Pascal': 4, 'Wildflower ': 10}
output = open('myfile.pkl', 'wb')
pickle.dump(mydict, output)
output.close()
Grüße Pascal
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Pascal hat geschrieben:2. "menu = int(raw_input(" > "))" ?? Dann kann man auch gleich input nehmen.
Nein, das sollte man nicht machen. So kann man ganz einfach den eventuellen `ValueError` abfangen und den Benutzer zu einer richtigen Eingabe auffordern. Andernfalls fliegt einem im günstigten(!) Fall nur das Skript an unerwarteter Stelle um die Ohren.
Pascal hat geschrieben:4. Den Highscore kann man schön leicht manipulieren :lol:
(nicht als txt speicher)
Pickle speichert keinen "Text", auch wenn es lesbar ist. Kryptische Binärdateien lassen sich auch nur geringfügig schwieriger manipulieren, mann muss nur die Muster finden. Und überschreiben ist eine unzulässige Idee. Vor allem, da einem das Skript um die Ohren fliegt, weil dein Datentyp nicht (mehr) dem von wildflower entspricht ;)
wildflower
User
Beiträge: 6
Registriert: Montag 1. Juni 2009, 11:06

hm, weiß nicht, ob ich das so ganz verstanden habe, aber sollte die schwierigkeitsfunktion in etwa so aussehen:

Code: Alles auswählen

def ermittle_schwierigkeitsgrad():
    print "\nSchwierigkeitsgrad waehlen:"
    print "_-_-_-_-_-_-_-_-_-_-_-_-_-_-"
    print "(1) leicht"
    print "(2) mittel"
    print "(3) schwer"
    schwgrad = int(raw_input(" > "))
    difficulty = 1
    while difficulty == 1:
        if schwgrad == 1:
            x = random.randint(1,100)
            versuche = 10
        elif schwgrad == 2:
            x = random.randint(1,1000)
            versuche = 11
        elif schwgrad == 3:
            x = random.randint(1,10000)
            versuche = 11
        else:
            print "\nDieser Schwierigkeitsgrad existiert nicht."
            difficulty = 0
            break
    return (x, versuche)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

In dieser Funktion brauchst du keine Schleife. Ob man 10 oder 11 Versuche hat, macht meiner Meinung nach keinen großen Unterschied. If-Else kannst du durch ein Dictionary gut vereinfachen (siehe Code von BlackJack). Aber am wichtigsten ist, dass du auf eine Schleife verzichtest, weil sie einfach überflüssig ist.
Antworten