Seite 1 von 1

zahlenratespiel

Verfasst: Montag 8. Juni 2009, 11:39
von wildflower
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()

Verfasst: Montag 8. Juni 2009, 11:57
von cofi
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").

Verfasst: Montag 8. Juni 2009, 12:34
von b.esser-wisser
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()

Verfasst: Montag 8. Juni 2009, 12:38
von cofi
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.

Verfasst: Montag 8. Juni 2009, 14:52
von wildflower
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()

Verfasst: Montag 8. Juni 2009, 15:12
von 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.

Verfasst: Montag 8. Juni 2009, 15:26
von Pascal
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

Verfasst: Montag 8. Juni 2009, 15:42
von cofi
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 ;)

Verfasst: Montag 8. Juni 2009, 16:37
von wildflower
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)

Verfasst: Montag 8. Juni 2009, 16:47
von derdon
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.