Search code examples
pythonsortingtkinterleaderboard

tkinter sorting txt file for leaderboard


I've been coding a multiplication game where you can practice multiplications. I'm trying to add in a leaderboard using an external txt file that would sort by the highest percentage but have been stuck for quite a while now. It's able to append the new data and show the results. The txt file is laid out as name, age, score (Jackie Welles, 16, 70%)

from tkinter import *
import random
from tkinter import messagebox

class Timestable:
    def __init__(self, parent):
        Timestable.f1 = Frame(parent)
        Timestable.f1.grid()

        Timestable.f2 = Frame(parent)
        Timestable.f2.grid()
        Timestable.f2.grid_forget()
        
        Timestable.f3 = Frame(parent)
        Timestable.f3.grid() 
        Timestable.f3.grid_forget()
    
#frame 1 ========================================================
        Label(self.f1,text="Multiplication Practice").grid()
        Label(self.f1,text="Name:").grid()
        Timestable.name = Entry (self.f1)
        Timestable.name.grid()
        Label(self.f1,text="Age").grid()
        Timestable.age = Entry (self.f1)
        Timestable.age.grid()
        
        
        Timestable.incorrect=[]
        Timestable.user = []
        
        Timestable.checked1 = IntVar()
        Timestable.checked2 = IntVar()
        self.c1 = Checkbutton(self.f1, text='1',variable=Timestable.checked1,onvalue=1,offvalue=0,command=lambda:data.save(self))
        self.c1.grid()
        self.c2 = Checkbutton(self.f1, text='2', variable=Timestable.checked2,onvalue=1,offvalue=0,command=lambda:data.save(self))
        self.c2.grid()

        Timestable.w = Spinbox(self.f1, from_=1, to=5)
        Timestable.w.grid()
        Button(self.f1,text="Start", command=lambda: data.start(self)).grid()
#frame 2 ========================================================
        Label(self.f2,text="Frame 2 ").grid()
        self.x=0
        self.correct=0
        sub = lambda: data.Submit(self)
        Button(self.f2,text="submit", command=sub).grid()
        Timestable.entryWidget = Entry (self.f2)
        Timestable.entryWidget.grid()

#frame 3 ========================================================
        Label(self.f3,text="Frame 3 ").grid()
        Timestable.congrats=Label(Timestable.f3,text="")
        Timestable.congrats.grid()
        Timestable.incdisplay = Label(Timestable.f3,text = Timestable.incorrect)
        Timestable.incdisplay.grid()
        Timestable.my_text=Text(self.f3,width=40,height=10)
        Timestable.my_text.grid()

class data:
    
    def openleader(self):      
        file=open('Leaderboard.txt',"a")
        file.write(Timestable.name.get()+", "+Timestable.age.get()+", "+str(data.percent)+"%""\n")
        file.close

        file=open("Leaderboard.txt","r")
        idk=file.readlines()
        Timestable.my_text.insert(END,idk)

    def save(self):
        if Timestable.checked1.get() == 1:
            Timestable.user.append(1)
        if Timestable.checked2.get() == 1:
            Timestable.user.append(2)

    def clear_text(self):
        Timestable.entryWidget.delete(0, 'end')

    
    def Questions(self): 
        number1 = random.choice(Timestable.user)
        number2 = random.randrange(1,12)
        self.answer = number1 * number2
        self.prompt = (str(number1) + " X " + str(number2))
        quest = Label(Timestable.f2, text=self.prompt, width=len(self.prompt))
        quest.grid()
        return self.answer

    def start(self):
        Timestable.f1.grid_forget() 
        Timestable.f2.grid()
        data.Questions(self)
        
    def results(self):
        Timestable.f2.grid_forget()
        Timestable.f3.grid()

    def Submit(self):
            if Timestable.entryWidget.get() == "":
                messagebox.showerror("Error", "Please enter a number.")

            else:
                if  self.answer != int(Timestable.entryWidget.get().strip()):
                    messagebox.showinfo("Answer", "INCORRECT! Answer: " + str(self.answer))
                    Timestable.incorrect.append(self.prompt)
                else:
                    messagebox.showinfo("Answer", "CORRECT!")
                    self.correct = self.correct +1
                self.x=self.x+1

                if self.x < int(Timestable.w.get()):
                    data.Questions(self)
                    data.clear_text(self)

                else:
                    data.results(self)
                    data.percent = round(self.correct/self.x*100)
                    Timestable.congrats.configure(text="Congrats, you got "+ str(data.percent) +"% of the questions correct")                    
                    Timestable.incdisplay.configure(text=Timestable.incorrect)
                    data.openleader(self)

root = Tk()
root.geometry("300x300")
Timestable(root)
data()
root.mainloop()

Solution

  • That can be added fairly easily. We can also clean up the way it is diplayed as well. Since you are already essentially storing the data in csv format we can stick to that structure when presenting the output data.

       def openleader(self):
            file=open('Leaderboard.txt',"a")
            file.write(Timestable.name.get()+", "+Timestable.age.get()+", "+str(data.percent)+"%""\n")
            file.close
            file=open("Leaderboard.txt","r").read()
            headers = " ".join(["Name", "Age", "Score"])
            output = [i.split(",") for i in file.split("\n") if i]
            out_sort = sorted(output, key=lambda x: int(x[2][:-1]), reverse=True)
            final = '\n'.join([headers, "-"*len(headers),*(" ".join(i) for i in out_sort)])
            Timestable.my_text.insert(END, final)