Ich finde den Fehler nicht!

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
Frodo1010
User
Beiträge: 4
Registriert: Freitag 11. Dezember 2020, 18:28

Moin zusammen,
also ich hab da ein kleines problem, ich wollte mir ein einfaches schere, stein, papier programm schreiben, ich hab angefangen und die GUI über Tkinter geschrieben, nach dem die fertig war hab ich sie getestet und siehe, da 3 Knöpfe und oben wird der Punkte stand in in Variablen angezeigt alles so wie es sein soll, ich schreib also die funktion das je nachdem für welches man sich entscheidet der gegner eine zufällige wahl trifft, dann sollte eine pop-up message kommen welche sagt ob du gewonnen verloren oder das gleiche gewählt hast und den punkte stand der variable dann ändern. als ich es testen wollte ist die konsole kurz aufgegangen und hat sich direkt wieder geschlossen und das wars, ich bekomm zwar die fehler meldung von wegen glaobal variable undefined module level aber ich kann damit nichts mehr wirklich anfangen.

Hier einmal mein Code:

from tkinter import *
from tkinter import messagebox
from tkinter.ttk import Notebook
import random

root = Tk()
root.wm_title("Schere, Stein, Papier")
root.config(background="#E0E0F8", width=50, height=50)

mypoint = 0
yourpoint = 0
genger = 0


def gewinner():
global mypoint
tkinter.messagebox.showinfo("Sieger", "Du hast Gewonnen!")
mypoint = mypoint + 1


def verlierer():
global yourpoint
tkinter.messagebox.showinfo("Verlierer", "Du hast Verloren!")
yourpoint = yourpoint + 1


def unentschieden():
tkinter.messagebox.showinfo("Unentschieden", "Ihr habt das gleiche gewählt!")


def sieger():
if wahl == 1:
if gegner == 1:
unentschieden()
if gegner == 2:
verlierer()
if gegner == 3:
gewinner()
if wahl == 2:
if gegner == 1:
gewinner()
if gegner == 2:
unentschieden()
if gegner == 3:
verlierer()
if wahl == 3:
if gegner == 1:
verlierer()
if gegner == 2:
gewinner()
if gegner == 3:
unentschieden()


def gegner():
global gegner
gegner = random.uniform(1, 3)


def schere():
global wahl
wahl = 1
sieger()


def stein():
global wahl
wahl = 2
sieger()


def papier():
global wahl
wahl = 3
sieger()


punkte = Label(root, text=str(mypoint) + " : " + str(yourpoint))
punkte.grid(row=0, column=1, padx=10, pady=5)

schere = Button(root, text="Schere", bg="#F78181", width=5, height=3, command=schere())
schere.grid(row=1, column=0, padx=8, pady=8)

stein = Button(root, text="Stein", bg="#F78181", width=5, height=3, command=stein())
stein.grid(row=1, column=1, padx=8, pady=8)

papier = Button(root, text="Papier", bg="#F78181", width=5, height=3, command=papier())
papier.grid(row=1, column=2, padx=8, pady=8)

root.mainloop()


ich sag dann schonmal Danke :)
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Bitte formatiere deinen Code auch als Code, er ist sonst unmöglich sinnvoll zu lesen. Ist dir das nach dem Abschicken des Posts nicht aufgefallen? Zum Formatieren gitbt es im Editor oberhalb des Editfeldes sogar einen Button der mit </> beschriftet ist.
ElektroBerry
User
Beiträge: 31
Registriert: Samstag 16. Mai 2020, 18:52

Benutze bitte die Codetags.

Code: Alles auswählen

def gegner():
global gegner
gegner = random.uniform(1, 3)
random.uniform gibt eine Float Zahl aus. random.randint() wolltest du sicherlich benutzen,
aber das beste ist vermutlich random.choice(["Schere", "Stein", "Papier"]).
Und dann kann die Funktion diesen Wert mit return zurückgeben.

Abgesehen davon, dass die Sieger Funktion einen schlechten Namen hat, könntest du dort auch Elif und Else benutzen.
Du fragst in der Funktion ständig die Gegner Variable ab, aber nirgends wird sie verändert.
Ausserdem wäre es doch schlau, wenn du die Funktion mit der Spieler_Auswahl aufrufen würdest.
Am Ende der Funktion könnte

Code: Alles auswählen

punkte.configure(text=f"{mypoint}:{yourpoint}")
stehen und es würde funktionieren.

Deine Buttons haben die selben Namen wie die Funktionen.
Und die Klammer muss entfernt werden bei Button(......command=....()), sonst wird die Funktion jedesmal sofort aufgerufen.

Hier noch etwas nützliches:

Code: Alles auswählen

WIN_CHOICES = {"Schere": "Papier", "Stein": "Papier", "Stein": "Schere"}
spieler_auswahl = "Papier"
computer_auswahl = "Schere"
if spieler_auswahl == computer_auswahl:
    print("Unentschieden.")
else:
    if WIN_CHOICES[spieler_auswahl] == computer_auswahl:
        print("Spieler gewinnt.")
    else:
        print("Computer gewinnt.")
Frodo1010
User
Beiträge: 4
Registriert: Freitag 11. Dezember 2020, 18:28

super vielen dank! ich werde es nachher mal probieren, und bei den nächsten fragen werde ich mein code auch formatieren :)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Warum nicht so?

Code: Alles auswählen

if ...:
	...
elif ...:
	...
else:
	...
In specifications, Murphy's Law supersedes Ohm's.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Bevor Du mit GUIs anfängst, solltest Du lernen, was Funktionen sind. Funktionen bekommen alles was sie brauchen über ihre Argumente und geben Ergebnisse per `return` zurück.
`global` hat in einem ordentlichen Programm nichts verloren.

Code: Alles auswählen

def ermittle_sieger(wahl, gegner):
    if wahl == gegner:
        return "unentschieden"
    elif (wahl, gegner) in [(1,3), (2,1), (3,2)]:
        return "gewonnen"
    else:
        return "verloren"
Und drumrum kann man dann ein Programm aufbauen:

Code: Alles auswählen

def main():
    mypoints = 0
    yourpoints = 0
    while True:
        wahl = int(input("1: Schere\n2: Stein\n3: Papier\n>"))
        gegner = random.randint(1,3)
        ergebnis = ermittle_sieger(wahl, gegner)
        print(ergebnis)
        if ergebnis == "gewonnen":
            mypoints += 1
        else:
            yourpoints += 1
        print(f"Punkte: {mypoints}:{yourpoints}")

if __name__ == '__main__':
    main()
Wenn Du jetzt noch eine GUI draufsetzen willst, brauchst Du erstmal Kenntnisse in Klasse-Definitionen. Denn irgendwo mußt Du ja den Zustand (also hier die Punkte) speichern.
Frodo1010
User
Beiträge: 4
Registriert: Freitag 11. Dezember 2020, 18:28

Moin einmal ein kurzes update, bisher läuft alles auser das mit dem punkte zählen, wenn ich in der funktion winner das

Code: Alles auswählen

mypoint = mypoint + 1 
und das

Code: Alles auswählen

yourpoint = yourpoint + 1
entferne läuft alles, ich verstehe aber nicht warum er wenn ich die variablen mypoint und yourpoint in der funktion global setze er mir die werte immernoch nicht speichert.

Code: Alles auswählen

from tkinter import *
from tkinter import messagebox
from tkinter.ttk import Notebook
import random

root = Tk()
root.wm_title("Schere, Stein, Papier")
root.config(background="#E0E0F8", width=50, height=50)

Win_Choice = {"Schere": "Papier", "Stein": "Schere", "Papier": "Stein"}
mypoint = 0
yourpoint = 0


def winner(spieler_wahl, gegner_wahl):
    if spieler_wahl == gegner_wahl:
        messagebox.showinfo("Unentschieden", "Unentschieden")
    else:
        if Win_Choice[spieler_wahl] == gegner_wahl:
            messagebox.showinfo("Gewonnen", "Du hast Gewonnen!")
			mypoint = mypoint + 1
        else:
            messagebox.showinfo("Verloren", "Du hast Verloren!")
			yourpoint = yourpoint + 1


def schere():
    spieler_wahl = "Schere"
    gegner_wahl = random.choice(["Schere", "Stein", "Papier"])
    winner(spieler_wahl, gegner_wahl)
    punkte.configure(text=f"{mypoint}:{yourpoint}")


def stein():
    spieler_wahl = "Stein"
    gegner_wahl = random.choice(["Schere", "Stein", "Papier"])
    winner(spieler_wahl, gegner_wahl)
    punkte.configure(text=f"{mypoint}:{yourpoint}")


def papier():
    spieler_wahl = "Papier"
    gegner_wahl = random.choice(["Schere", "Stein", "Papier"])
    winner(spieler_wahl, gegner_wahl)
    punkte.configure(text=f"{mypoint}:{yourpoint}")


punkte = Label(root, text=str(mypoint) + " : " + str(yourpoint))
punkte.grid(row=0, column=1, padx=10, pady=5)

schere = Button(root, text="Schere", bg="#F78181", width=5, height=3, command=schere)
schere.grid(row=1, column=0, padx=8, pady=8)

stein = Button(root, text="Stein", bg="#F78181", width=5, height=3, command=stein)
stein.grid(row=1, column=1, padx=8, pady=8)

papier = Button(root, text="Papier", bg="#F78181", width=5, height=3, command=papier)
papier.grid(row=1, column=2, padx=8, pady=8)

root.mainloop() 
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine *-Importe. global solltest Du erst gar nicht verwenden. Für GUIs brauchst Du Klassen. Notfalls kann man für einfache Programme auch mit Argumenten arbeiten.
In Deinem Programm hast Du viel kopierten Code. Schere, Stein und Papier sollten am besten nur einmal vorkommen.

Code: Alles auswählen

import tkinter as tk
from tkinter import messagebox
import random
from functools import partial

WIN_CHOICES = {"Schere": "Papier", "Stein": "Schere", "Papier": "Stein"}

def click(spieler_wahl, punkte):
    gegner_wahl = random.choice(list(WIN_CHOICES))
    mypoints, yourpoints = map(int, punkte['text'].split(':'))
    if spieler_wahl == gegner_wahl:
        messagebox.showinfo("Unentschieden", "Unentschieden")
    elif WIN_CHOICES[spieler_wahl] == gegner_wahl:
        messagebox.showinfo("Gewonnen", "Du hast Gewonnen!")
        mypoints += 1
    else:
        messagebox.showinfo("Verloren", "Du hast Verloren!")
        yourpoints += 1
    punkte['text'] = f"{mypoints}:{yourpoints}"


def main():
    root = tk.Tk()
    root.wm_title("Schere, Stein, Papier")
    root.config(background="#E0E0F8", width=50, height=50)
    punkte = tk.Label(root, text="0:0")
    punkte.grid(row=0, column=1, padx=10, pady=5)
    for column, symbol in enumerate(WIN_CHOICES):
        button = tk.Button(root, text=symbol, bg="#F78181", width=5, height=3, command=partial(click, symbol, punkte))
        button.grid(row=1, column=column, padx=8, pady=8)
    root.mainloop() 

if __name__ == '__main__':
    main()
ElektroBerry
User
Beiträge: 31
Registriert: Samstag 16. Mai 2020, 18:52

Entweder benutzt du bei jeder Funktion ein:

Code: Alles auswählen

global mypoint
global yourpoint
oder die vernünftige Lösung um das global zu vermeiden, man schreibt eine Klasse für das Spiel.

Code: Alles auswählen

import tkinter
from tkinter import messagebox
import random


class SchereSteinPapier():
    def __init__(self):
        self.root = tkinter.Tk()
        self.root.wm_title("Schere, Stein, Papier")
        self.root.config(background="#E0E0F8", width=50, height=50)
        
        self.computer_punkte = 0
        self.spieler_punkte = 0

        self.punkte = tkinter.Label(self.root, text="0:0")
        self.punkte.grid(row=0, column=1, padx=10, pady=5)

        self.button_schere = tkinter.Button(self.root, text="Schere", bg="#F78181",
                                            width=5, height=3,
                                            command= lambda: self.turn("Schere"))
        self.button_schere.grid(row=1, column=0, padx=8, pady=8)
        self.button_stein = tkinter.Button(self.root, text="Stein", bg="#F78181",
                                           width=5, height=3,
                                           command= lambda: self.turn("Stein"))
        self.button_stein.grid(row=1, column=1, padx=8, pady=8)
        self.button_papier = tkinter.Button(self.root, text="Papier", bg="#F78181",
                                            width=5, height=3, 
                                            command= lambda: self.turn("Papier"))
        self.button_papier.grid(row=1, column=2, padx=8, pady=8)
        self.root.mainloop()


    def turn(self, spieler_auswahl):
        WIN_CHOICES = {"Schere": "Papier", "Stein": "Papier", "Papier": "Schere"}
        computer_auswahl = random.choice(["Schere", "Stein", "Papier"])
        if spieler_auswahl == computer_auswahl:
            messagebox.showinfo("Unentschieden", "Ihr habt dasselbe gewählt!")
        elif WIN_CHOICES[spieler_auswahl] == computer_auswahl:
            messagebox.showinfo("Sieger", "Du hast Gewonnen!")
            self.computer_punkte += 1
        else:
            messagebox.showinfo("Verlierer", "Du hast Verloren!")
            self.spieler_punkte += 1
        self.punkte.configure(text=f"{self.computer_punkte}:{self.spieler_punkte}")
    

def main():
    SchereSteinPapier()


if __name__ == "__main__":
    main()
Meiner Meinung nach müsste ich hier die wichtigsten Python-Konventionen eingehalten haben.
Frodo1010
User
Beiträge: 4
Registriert: Freitag 11. Dezember 2020, 18:28

kurze frage nochmal, dein code kann ich soweit lesen und verstehen, ich werds gleich mal versuchen, ich versteh nur nicht ganz was das mit der _Main_ auf sich hat und was meinst du mit was ich über klassen wissen sollte für eine GUI? also ich hab ganz schön dicken schicken zu python3 rein lesen könnte ich mich da ohne probleme nur ich weis nicht genau wo ich anfangen soll
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@ElektroBerry: __init__ ist dazu da, etwas zu initialisieren, nicht dass das dauerhaft läuft. Das mainloop gehört da nicht rein. Statt lambda-Funktionen sollte man functools.partial verwenden.
Antworten