3
\$\begingroup\$

I'm very new to python and programming in general. For a school assignment, I made this Memory Game and would love to receive feedback from you guys.

import tkinter as tk  # imports tkinter as tk
from tkinter import font as tkfont  # imports font as tkfont
import random  # imports random
import string  # imports string
import sys  # imports sys
import time  # imports time
import pygame  # imports pygame (enables me to use its functions)

pygame.mixer.pre_init(44100, 16, 2, 4096)  # Enables me to use music in pygame
pygame.init()  # Enables me to use music in pygame

button_click = pygame.mixer.Sound('151022__bubaproducer__laser-shot-silenced.wav')
# Loads '151022__bubaproducer__laser-shot-silenced.wav' file
button_click2 = pygame.mixer.Sound('Mario Coin.wav')  # Makes button_click2 play 'Mario Coin.wav' file

 pygame.mixer.music.load('merge_from_ofoct.mp3')  # Loads my music file
 pygame.mixer.music.play(-1)  # -1 plays the song infinitely
 pygame.mixer.music.set_volume(0.8)  # Sets the volume of the music


def logout_logout():  # Defines logout_logout
    entUsername.delete(0, tk.END)  # Deletes past entry's in the Username entry box
    entPassword.delete(0, tk.END)  # Deletes past entry's in the Password entry box
    entUsername.focus_set()  # Makes it so the Username entry box is targeted

def play_music1():  # Defines play_music1
    pygame.mixer.music.load('merge_from_ofoct.mp3')  # Loads 'merge_from_ofoct.mp3' file
    pygame.mixer.music.play(-1)  # Makes the song play infinitely
    pygame.mixer.music.set_volume(0.8)  # Sets the volume (volume can be adjusted from 0-1)

def play_music2():  # Defines play_music2
    pygame.mixer.music.load('251461__joshuaempyre__arcade-music-loop.wav')
    # Loads '251461__joshuaempyre__arcade-music-loop.wav3' file
    pygame.mixer.music.play(-1)  # Makes the song play infinitely
    pygame.mixer.music.set_volume(0.8)  # Sets the volume (volume can be adjusted from 0-1)

def play_music3():  # Defines play_music3
    pygame.mixer.music.load('Off Limits.wav')  # Loads 'Off Limits.wav') file
    pygame.mixer.music.play(-1)  # Makes the song play infinitely
    pygame.mixer.music.set_volume(0.8)  # Sets the volume (volume can be adjusted from 0-1)

def play_music4():  # Defines play_music4
    pygame.mixer.music.load('Pim Poy.wav')  # Loads 'Pim Poy.wav') file
    pygame.mixer.music.play(-1)  # Makes the song play infinitely
    pygame.mixer.music.set_volume(0.8)  # Sets the volume (volume can be adjusted from 0-1)

def play_music5():  # Defines play_music5
    pygame.mixer.music.load('Puzzle-Game.mp3')  # Loads 'Puzzle-Game.mp3') file
    pygame.mixer.music.play(-1)  # Makes the song play infinitely
    pygame.mixer.music.set_volume(0.8)  # Sets the volume (volume can be adjusted from 0-1)

def return_to_main_menu2():  # Defines return_to_main_menu2
    pygame.mixer.Sound.play(button_click2).set_volume(0.8)  # Plays button_click2/sets the volume of the song

def return_to_main_menu():  # Defines return_to_main_menu
    pygame.mixer.Sound.play(button_click).set_volume(0.6)  # Plays button_click/sets the volume of the sound

def random_char(y):  # Defines random_char
    return ''.join(random.choice(string.ascii_letters) for x in range(y))

x = (random_char(6))  # Spawns 6 random characters
word = x  # Makes word=x

Class #1

class SampleApp(tk.Tk):  # Class - Basically my Main hub

def __init__(self, *args, **kwargs):  # Arguments is controller and kwargs are keyword arguments
    tk.Tk.__init__(self, *args, **kwargs)  # Arguments is controller and kwargs are keyword arguments
    self.geometry("1920x1080")  # Size of the window when the programs run
    self.title("Memory Mania")  # Puts "Memory Mania" in the top left of the window

    self.title_font = tkfont.Font(family='verdana', size=45, weight="bold", slant="italic")
    # Whenever i use use "font=controller.title_font", this font will be used

    container = tk.Frame(self)  # Defines it
    container.pack(side="top", fill="both", expand=True)  # Packs it
    container.grid_rowconfigure(0, weight=1)  # Changes the size
    container.grid_columnconfigure(0, weight=1)  # Changes the size

    self.frames = {}  # Below this is all my classes, if the class isn't listed here it wont show
    for F in (Login, MainMenu, Tutorial, Tutorial2, Difficulty, Settings, Music, EasyDifficulty, MediumDifficulty,
              HardDifficulty, InsaneDifficulty, EnterCharacterScreen, CorrectScreen, IncorrectScreen, Level2,
              WinGameScreen):

        page_name = F.__name__  # Makes page_name = F._name_
        frame = F(parent=container, controller=self)  # frame = F(parent=container, controller=self)
        self.frames[page_name] = frame  # self.frame(page_name) = frame

        frame.grid(row=0, column=0, sticky="nsew")  # the frames grid size

    self.show_frame("Login")  # Shows the Login screen as the first screen

def show_frame(self, page_name):  # Shows a frame for the given page name
    frame = self.frames[page_name]  # Makes frame = self.frames(page_name)
    frame.tkraise()  # Raises the frame

Class #2

class Login(tk.Frame):  # Class - My Login screen

def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller  = controller

    background_image = tk.PhotoImage(file="9a4a50632b464e426a71c800f80ad778.png")
    background_label = tk.Label(self, image=background_image)
    background_label.place(x=0, y=0, relwidth=1, relheight=1)

    background_label.image = background_image

    def login_button():  # Defines login_button
        controller.show_frame("MainMenu"), return_to_main_menu2()
        your_username = entUsername.get()
        username_label.configure(text=your_username)
        # Shows MainMenu and uses return_to_main_menu2 function

    def login_button2(event):  # Defines login_button2 and marks it as an event
        controller.show_frame("MainMenu"), return_to_main_menu2()
        your_username = entUsername.get()
        username_label.configure(text=your_username)
        # Shows MainMenu and uses return_to_main_menu2 function

    lbl1 = tk.Label(self, text=" ", fg="white", bg="black")  # Bg="#2699C3" is another form of blue
    # These labels are used to create blank spaces to centre my program
    lbl1.pack()  # Packs the label wherever there's space
    lbl2 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl2.pack()  # Packs the label wherever there's space
    lbl3 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl3.pack()  # Packs the label wherever there's space
    lbl4 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl4.pack()  # Packs the label wherever there's space
    lbl5 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl5.pack()  # Packs the label wherever there's space
    lbl6 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl6.pack()  # Packs the label wherever there's space
    lbl7 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl7.pack()  # Packs the label wherever there's space
    lbl8 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl8.pack()  # Packs the label wherever there's space
    lblUsername = tk.Label(self, text="Username:", fg="white", bg="black")  # Makes the Label display Username
    lblUsername.place(anchor="center")  # Centers the label
    global entUsername  # Changes entUsername to a global variable (global variables can be used in all classes)
    entUsername = tk.Entry(self, justify="center")  # Centers the entry box
    lblUsername.pack()  # Packs it wherever there's space
    lblUsername.config(font=("Courier", 32))  # Changes the font/size
    entUsername.pack()  # Packs it wherever there's space
    entUsername.config(font=("Courier", 32))  # Changes the font/size
    lblPassword = tk.Label(self, text="Password:", fg="white", bg="black")  # Makes the Label display Password
    lblPassword.place(anchor="center")  # Centers the label
    global entPassword  # Changes entPassword to a global variable
    entPassword = tk.Entry(self, justify="center")  # Centers the entry box
    lblPassword.pack()  # Packs it wherever there's space
    lblPassword.config(font=("Courier", 32))  # Changes the font/size
    entPassword.pack()  # Packs it wherever there's space
    entPassword.config(font=("Courier", 32))  # Changes the font/size
    entUsername.focus_set()
    entPassword.bind("<Return>", login_button2)

    btn = tk.Button(self, text="Login", fg="black", bg="lawn green", width=6, height=1,  # Changes colour
                    command=login_button)  # Uses login_button function

    btn.pack(pady=10)  # How many pixels to pad widget, vertically

Class #3

class MainMenu(tk.Frame):  # Class - My Main Menu screen

def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller  = controller

    label = tk.Label(self, text="Memory Mania", font=controller.title_font, bg="#2699C3")
    # Puts Memory Mania as a large Label
    label.pack(side="top", fill="x", pady=10)  # Packs the label at the top of the program
    global username_label  # Makes username_label a global variable
    label1 = tk.Label(self, text="Logged in as:", bg="#2699C3")  # Changes colour
    label1.pack()  # Packs the label wherever there's space
    username_label = tk.Label(self, text=" ", bg="#2699C3")  # Users username is posted here
    username_label.pack()  # Packs the label wherever there's space

    def get_answer2(event):
        if entry_characters.get() == word:  # Tells program that if the entry of characters = the correct/incorrect
            controller.show_frame("CorrectScreen")  # Show correct screen (if answer is correct)
        else:
            controller.show_frame("IncorrectScreen")  # Show incorrect screen (if answer is wrong)

    def start_game():
        pygame.mixer.Sound.play(button_click).set_volume(0.6)
        controller.show_frame("Difficulty")
        entry_characters.bind("<Return>", get_answer2)  # Makes you able to click enter

    button1 = tk.Button(self, text="Play", bg="#76EE00", fg="black", height=4, width=20,  # Changes colour/size
                        command=start_game)
    # Makes this button take me to the Difficulty screen and uses the 'return_to_main_menu' function
    button2 = tk.Button(self, text="Tutorial", bg="yellow", fg="black", height=4, width=20,  # Changes colour/size
                        command=lambda: [controller.show_frame("Tutorial"), return_to_main_menu()])
    # Makes this button take me to the Tutorial screen and uses the 'return_to_main_menu function'
    button3 = tk.Button(self, text="Settings", bg="#00EEEE", fg="black", height=4, width=20,  # Changes colour/size
                        command=lambda: [controller.show_frame("Settings"), return_to_main_menu()])
    # Makes this button take me to the Settings screen and uses the 'return_to_main_menu function'
    button4 = tk.Button(self, text="Logout", bg="orange", fg="black", height=4, width=20,  # Changes colour/size
                        command=lambda: [controller.show_frame("Login"), logout_logout()])
    # Makes this button take me to the Login screen and uses the 'logout_logout' function
    button5 = tk.Button(self, text="Quit", bg="red", fg="black", height=4, width=20, cursor="pirate",
                        # Changes colour/size/cursor
                        command=sys.exit)
    # Makes this button Quit the program

    button1.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button1.config(font=("System", 10))  # Changes font/size
    button2.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button2.config(font=("System", 10))  # Changes font/size
    button3.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button3.config(font=("System", 10))  # Changes font/size
    button4.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button4.config(font=("System", 10))  # Changes font/size
    button5.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button5.config(font=("System", 10))  # Changes font/size

Class #4

class Tutorial(tk.Frame):  # Class - My Tutorial screen

def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller   # Makes self.controller  = controller

    # These labels are used to create blank spaces to centre my program
    lbl1 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl1.pack()  # Packs it wherever there's space
    lbl2 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl2.pack()  # Packs it wherever there's space
    lbl3 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl3.pack()  # Packs it wherever there's space

    label = tk.Label(self, text="Tutorial (1)", font=controller.title_font, bg="#2699C3")  # Changes font/colour
    label1 = tk.Label(self, text="Once you click the Play button you will be brought to the Difficulty screen",
                      bg="#2699C3")  # Changes text/colour
    label2 = tk.Label(self, text="Once you're in the Difficulty screen, you can select 1 of 4 Difficulties",
                      bg="#2699C3")  # Changes text/colour
    label3 = tk.Label(self, text="Easy, Medium, Hard, Insane, all which have 5 levels",
                      bg="#2699C3")  # Changes text/colour

    label.pack(side="top", fill="x", pady=10)
    # How many pixels to pad widget, vertically/horizontally and at the top
    label1.pack(side="top", fill="x", pady=10)
    # How many pixels to pad widget, vertically/horizontally
    label2.pack(side="top", fill="x", pady=10)
    # How many pixels to pad widget, vertically/horizontally
    label3.pack(side="top", fill="x", pady=10)
    # How many pixels to pad widget, vertically/horizontally
    label1.config(font=("System", 14))  # Changes font/size
    label2.config(font=("System", 14))  # Changes font/size
    label3.config(font=("System", 14))  # Changes font/size

    button1 = tk.Button(self, text="Next Page", bg="yellow", fg="black", height=4, width=20,
                        # Changes colour/size of button
                        command=lambda: [controller.show_frame("Tutorial2"), return_to_main_menu()])
    # Makes this button take me to Tutorial2 screen and uses the 'return_to_main_menu' function
    button2 = tk.Button(self, text="Return to Main Menu", bg="yellow", fg="black", height=4, width=20,
                        # Changes colour/size of button
                        command=lambda: [controller.show_frame("MainMenu"), return_to_main_menu()])
    # Makes this button take me to the Main Menu and uses the 'return_to_main_menu' function
    label4 = tk.Label(self, text="Note: Lowercase and Capital letters matter!", bg="#2699C3")  # Changes colour
    label4.config(font=("System", 10))  # Changes font/size
    label4.pack(side="bottom", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontal

    button1.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button1.config(font=("System", 10))  # Changes font/size
    button2.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button2.config(font=("System", 10))  # Changes font/size

Class #6

class Difficulty(tk.Frame):  # Class - My Difficulty screen

def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller  = controller

    label = tk.Label(self, text="Difficulty", font=controller.title_font, bg="#2699C3")  # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally

    def wait_fifteen_seconds():  # Defines "wait_fifteen_seconds"
        label_check.configure(text="Level 1")  # Configures the label to the level specified
        global seconds_to_wait  # Changes "seconds_to_wait" to a global variable
        # Changes "seconds_to_wait" to a global variable meaning you can use it in all classes
        seconds_to_wait = 15  # Makes the screen change in 15 seconds
        entry_characters.delete(0, tk.END)  # Gets rid of the past entry's
        x = (random_char(6))  # Generates 6 random characters
        global word  # Changes "word" to a global variable
        word = x  # Makes word=x
        label2_easy.configure(text=word)  # Configures the label to show the "word" variable
        controller.show_frame("EasyDifficulty"), return_to_main_menu()  # Displays the "EasyDifficulty screen"
        entry_characters.pack_forget()  # Makes you unable to enter the characters before the screen appears
        app.update()  # Updates the program
        time.sleep(seconds_to_wait)  # Makes the program wait for however many seconds depending on difficulty
        controller.show_frame("EnterCharacterScreen")  # Displays the "EnterCharacterScreen"
        entry_characters.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
        button_submit.pack(fill=tk.X, padx=80, pady=80, side=tk.BOTTOM)
        # How many pixels to pad widget, vertically/horizontally
        entry_characters.focus_set()  # Automatically clicks the entry box

    def wait_ten_seconds():  # Defines "wait_ten_seconds"
        label_check.configure(text="Level 1 ")  # Configures the label to the level specified
        global seconds_to_wait  # Changes "seconds_to_wait" to a global variable
        # Changes "seconds_to_wait" to a global variable meaning you can use it in all classes
        seconds_to_wait = 10  # Makes the screen change in 10 seconds
        entry_characters.delete(0, tk.END)  # Gets rid of the past entry's
        x = (random_char(6))  # Generates 6 random characters
        global word  # Changes "word" to a global variable meaning you can use it in all classes
        word = x  # Makes word=x
        label2_medium.configure(text=word)  # Configures the label to show the "word" variable
        controller.show_frame("MediumDifficulty"), return_to_main_menu()  # Displays the "MediumDifficulty screen"
        entry_characters.pack_forget()  # Makes you unable to enter the characters before the screen appears
        app.update()  # Updates the program
        time.sleep(seconds_to_wait)  # Makes the program wait for however many seconds depending on difficulty
        controller.show_frame("EnterCharacterScreen")  # Displays the "EnterCharacterScreen"
        entry_characters.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
        button_submit.pack(fill=tk.X, padx=80, pady=80, side=tk.BOTTOM)
        # How many pixels to pad widget, vertically/horizontally
        entry_characters.focus_set()  # Automatically clicks the entry box

    def wait_five_seconds():  # Defines "wait_five_seconds"
        label_check.configure(text="Level 1 ")  # Configures the label to the level specified
        global seconds_to_wait  # Changes "seconds_to_wait" to a global variable
        # Changes "seconds_to_wait" to a global variable meaning you can use it in all classes
        seconds_to_wait = 5  # Makes the screen change in 5 seconds
        entry_characters.delete(0, tk.END)  # Gets rid of the past entry's
        x = (random_char(6))  # Generates 6 random characters
        global word  # Changes "word" to a global variable meaning you can use it in all classes
        word = x  # Makes word=x
        label2_hard.configure(text=word)  # Configures the label to show the "word" variable
        controller.show_frame("HardDifficulty"), return_to_main_menu()  # Displays the "HardDifficulty screen"
        entry_characters.pack_forget()  # Makes you unable to enter the characters before the screen appears
        app.update()  # Updates the program
        time.sleep(seconds_to_wait)  # Makes the program wait for however many seconds depending on difficulty
        controller.show_frame("EnterCharacterScreen")  # Displays the "EnterCharacterScreen"
        entry_characters.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
        button_submit.pack(fill=tk.X, padx=80, pady=80, side=tk.BOTTOM)
        # How many pixels to pad widget, vertically/horizontally
        entry_characters.focus_set()  # Automatically clicks the entry box

    def wait_two_seconds():  # Defines "wait_two_seconds"
        label_check.configure(text="Level 1")  # Configures the label to the level specified
        global seconds_to_wait  # Changes "seconds_to_wait" to a global variable
        # Changes "seconds_to_wait" to a global variable meaning you can use it in all classes
        seconds_to_wait = 2  # Makes the screen change in 2 seconds
        entry_characters.delete(0, tk.END)  # Gets rid of the past entry's
        x = (random_char(6))  # Generates 6 random characters
        global word  # Changes "word" to a global variable meaning you can use it in all classes
        word = x  # Makes word=x
        label2_insane.configure(text=word)  # Configures the label to show the "word" variable
        controller.show_frame("InsaneDifficulty"), return_to_main_menu()  # Displays the "InsaneDifficulty screen"
        entry_characters.pack_forget()  # Makes you unable to enter the characters before the screen appears
        app.update()  # Updates the program
        time.sleep(seconds_to_wait)  # Makes the program wait for however many seconds depending on difficulty
        controller.show_frame("EnterCharacterScreen")  # Displays the "EnterCharacterScreen"
        entry_characters.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
        button_submit.pack(fill=tk.X, padx=80, pady=80, side=tk.BOTTOM)
        #   How many pixels to pad widget, vertically/horizontally
        entry_characters.focus_set()  # Automatically clicks the entry box

    button = tk.Button(self, text="Easy", bg="yellow", fg="black", height=4, width=20,
                       command=wait_fifteen_seconds)
    # Makes button wait fifteen seconds/changes text/colour/size
    button1 = tk.Button(self, text="Medium", bg="#E99B15", fg="black", height=4, width=20, command=wait_ten_seconds)
    # Makes button wait ten seconds/changes text/colour/size
    button2 = tk.Button(self, text="Hard", bg="#C04141", fg="black", height=4, width=20, command=wait_five_seconds)
    # Makes button wait five seconds/changes text/colour/size
    button3 = tk.Button(self, text="Insane", bg="#FC0000", fg="black", height=4, width=20, command=wait_two_seconds)
    # Makes button wait two seconds/changes text/colour/size
    button4 = tk.Button(self, text="Back", bg="green", fg="black", height=4, width=20,
                        command=lambda: [controller.show_frame("MainMenu"), return_to_main_menu()])
    # Makes this button take me to the MainMenu and uses the 'return_to_main_menu' function

    button.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button.config(font=("System", 10))  # Changes font/size
    button1.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button1.config(font=("System", 10))  # Changes font/size
    button2.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button2.config(font=("System", 10))  # Changes font/size
    button3.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button3.config(font=("System", 10))  # Changes font/size
    button4.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button4.config(font=("System", 10))  # Changes font/size

Class #7

class Settings(tk.Frame):  # Class - My Settings screen

def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller

    lbl1 = tk.Label(self, text=" ", fg="white", bg="#2699C3")
    lbl1.pack()  # Packs the label wherever there's space
    lbl2 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl2.pack()  # Packs the label wherever there's space
    lbl3 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl3.pack()  # Packs the label wherever there's space

    label = tk.Label(self, text="Settings", font=controller.title_font, bg="#2699C3")  # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally

    button1 = tk.Button(self, text="Pause Music", bg="red", fg="white", height=4, width=20,  # Changes colour/size
                        command=pygame.mixer.music.pause)
    # Pauses the current song
    button2 = tk.Button(self, text="Resume Music", bg="green", fg="white", height=4, width=20,  # Colour/size
                        command=pygame.mixer.music.unpause)
    # Resumes the current song
    button3 = tk.Button(self, text="Music", bg="yellow", fg="black",
                        height=4, width=20,  # Colour/size
                        command=lambda: [controller.show_frame("Music"), return_to_main_menu()])
    # Makes this button take me to the Music screen and play the 'return_to_main_menu' function
    button = tk.Button(self, text="Back", bg="#00EEEE", fg="black", height=4, width=20,  # Changes colour/size
                       command=lambda: [controller.show_frame("MainMenu"), return_to_main_menu()])
    # Makes this button take me to the Main Menu and play the 'return_to_main_menu function

    label1 = tk.Label(self, text="Note: Music takes a few seconds to start up!", bg="#2699C3")  # Changes colour
    label1.config(font=("System", 10))  # Changes font/size
    label1.pack(side="bottom", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally

    button1.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button1.config(font=("System", 10))  # Changes font/size
    button2.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button2.config(font=("System", 10))  # Changes font/size
    button3.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button3.config(font=("System", 10))  # Changes font/size
    button.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button.config(font=("System", 10))  # Changes font/size

Class #8

class Music(tk.Frame):  # Class - My Music screen

def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller

    label = tk.Label(self, text="Music", font=controller.title_font, bg="#2699C3")  # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally

    button1 = tk.Button(self, text="Soundtrack 1", bg="#0000FF", fg="white", height=4, width=20,
                        # Changes colour/size
                        command=play_music1)
    # plays the function 'play_music1'
    button2 = tk.Button(self, text="Soundtrack 2", bg="#EE3B3B", fg="white", height=4, width=20,
                        # Changes colour/size
                        command=play_music2)
    # plays the function 'play_music2'
    button3 = tk.Button(self, text="Soundtrack 3", bg="#7AC5CD", fg="white", height=4, width=20,
                        # Changes colour/size
                        command=play_music3)
    # plays the function 'play_music3'
    button4 = tk.Button(self, text="Soundtrack 4", bg="#00C957", fg="white", height=4, width=20,
                        # Changes colour/size
                        command=play_music4)
    # plays the function 'play_music4'
    button5 = tk.Button(self, text="Soundtrack 5", bg="#FFB90F", fg="white", height=4, width=20,
                        # Changes colour/size
                        command=play_music5)
    # plays the function 'play_music5'
    button = tk.Button(self, text="Return", bg="#00EEEE", fg="black", height=4, width=20,  # Changes colour/size
                       command=lambda: [controller.show_frame("Settings"), return_to_main_menu()])

    button1.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button1.config(font=("System", 10))  # Changes font/size
    button2.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button2.config(font=("System", 10))  # Changes font/size
    button3.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button3.config(font=("System", 10))  # Changes font/size
    button4.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button4.config(font=("System", 10))  # Changes font/size
    button5.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button5.config(font=("System", 10))  # Changes font/size
    button.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button.config(font=("System", 10))  # Changes font/size

Class #9

class EasyDifficulty(tk.Frame):  # Class - My EasyDifficulty screen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller

    label_level = tk.Label(self, text="Level 1", bg="#2699C3")  # Changes colour
    label_level.pack()  # Packs the label wherever there's space
    label = tk.Label(self, text="Remember these characters", font=controller.title_font, bg="#2699C3")
    # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally
    global label2_easy  # Global variable
    label2_easy = tk.Label(self, height=4, width=15, text=word)  # Changes size, text = word
    label2_easy.config(font=("Courier", 64))  # Changes font/size
    label2_easy.pack()  # Packs the label wherever there's space

Class #10

class MediumDifficulty(tk.Frame):  # Class - My MediumDifficulty screen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller

    label_level = tk.Label(self, text="Level 1", bg="#2699C3")  # Changes colour
    label_level.pack()  # Packs the label wherever there's space
    label = tk.Label(self, text="Remember these characters", font=controller.title_font, bg="#2699C3")
    # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally
    global label2_medium  # Global variable
    label2_medium = tk.Label(self, height=4, width=15, text=word)   # Changes size, text = word
    label2_medium.config(font=("Courier", 64))  # Changes font/size
    label2_medium.pack()  # Packs the label wherever there's space

Class #11

class HardDifficulty(tk.Frame):  # Class - My HardDifficulty screen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller

    label_level = tk.Label(self, text="Level 1", bg="#2699C3")  # Changes colour
    label_level.pack()  # Packs the label wherever there's space
    label = tk.Label(self, text="Remember these characters", font=controller.title_font, bg="#2699C3")
    # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally
    global label2_hard  # Global variable
    label2_hard = tk.Label(self, height=4, width=15, text=word)  # Changes size, text = word
    label2_hard.config(font=("Courier", 64))  # Changes font/size
    label2_hard.pack()  # Packs the label wherever there's space

Class #12

class InsaneDifficulty(tk.Frame):  # Class - My InsaneDifficulty screen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller

    label_level = tk.Label(self, text="Level 1", bg="#2699C3")  # Changes colour
    label_level.pack()  # Packs the label wherever there's space
    label = tk.Label(self, text="Remember these characters", font=controller.title_font, bg="#2699C3")
    # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally
    global label2_insane  # Global variable
    label2_insane = tk.Label(self, height=4, width=15, text=word)  # Changes size, text = word
    label2_insane.config(font=("Courier", 64))  # Changes font/size
    label2_insane.pack()  # Packs the label wherever there's space

Class #13

class EnterCharacterScreen(tk.Frame):  # Class - My EnterCharacterScreen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller
    # These labels are used to create blank spaces to centre my program
    lbl1 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl1.pack()  # Packs label wherever there's space
    lbl2 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl2.pack()  # Packs label wherever there's space
    lbl3 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl3.pack()  # Packs label wherever there's space
    lbl4 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl4.pack()  # Packs label wherever there's space
    lbl5 = tk.Label(self, text=" ", fg="white", bg="#2699C3")  # Changes colour of label
    lbl5.pack()  # Packs label wherever there's space
    label = tk.Label(self, text="What were your characters?", font=controller.title_font, bg="#2699C3")
    # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally

    def get_answer():  # Defines get_answer
        if entry_characters.get() == word:  # Tells program that if the entry of characters = the correct/incorrect
            controller.show_frame("CorrectScreen")  # Show correct screen (if answer is correct)
        else:
            controller.show_frame("IncorrectScreen")  # Show incorrect screen (if answer is wrong)

    def get_answer2(event):  # Defines get_answer (event is needed so users can click enter when submitting)
        if entry_characters.get() == word:  # Tells program that if the entry of characters = the correct/incorrect
            controller.show_frame("CorrectScreen")  # Show correct screen (if answer is correct)
        else:
            controller.show_frame("IncorrectScreen")  # Show incorrect screen (if answer is wrong)

    global entry_characters  # Global variable
    entry_characters = tk.Entry(self, justify="center")  # Centers the entry
    entry_characters.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    entry_characters.config(font=("Courier", 96))  # Changes the font/size
    entry_characters.bind("<Return>", get_answer2)  # Makes you able to click enter
    global button_submit  # Global variable
    button_submit = tk.Button(self, text="Submit", command=get_answer, height=4, width=20)  # Changes size of button
    button_submit.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button_submit.config(font=("System", 10))  # Changes the font/size

Class #14

class CorrectScreen(tk.Frame):  # Class - My CorrectScreen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="green")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller
    # These labels are used to create blank spaces to centre my program
    lbl1 = tk.Label(self, text=" ", fg="white", bg="green")  # Changes colour of label
    lbl1.pack()  # Packs label wherever there's space
    lbl2 = tk.Label(self, text=" ", fg="white", bg="green")  # Changes colour of label
    lbl2.pack()  # Packs label wherever there's space
    lbl3 = tk.Label(self, text=" ", fg="white", bg="green")  # Changes colour of label
    lbl3.pack()  # Packs label wherever there's space
    lbl4 = tk.Label(self, text=" ", fg="white", bg="green")  # Changes colour of label
    lbl4.pack()  # Packs label wherever there's space

    label = tk.Label(self, text="CORRECT!!:)", font=controller.title_font, bg="green")  # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally

    def next_level_two():  # Defines next_level_two
        label_check.configure(text="Level 2")  # Shows Level 2 at the top
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen
        button_next_screen.configure(command=next_level_three)  # Shows Level 3 screen
        button_lose.configure(command=difficulty_change)  # Shows Difficulty screen
        button_tutorial_lose.configure(command=tutorial_show)  # Shows Tutorial screen
        button_main_lose.configure(command=main_menu)  # Shows Main Menu

    def next_level_three():  # Defines next_level_three
        label_check.configure(text="Level 3")  # Shows Level 3 at the top
        button_next_screen.configure(command=next_level_four)  # Shows Level 4 screen
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen

    def next_level_four():  # Defines next_level_four
        label_check.configure(text="Level 4")  # Shows Level 4 at the top
        button_next_screen.configure(command=next_level_five)  # Shows Level 5 screen
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen

    def next_level_five():  # Defines next_level_five
        entry_characters.bind("<Return>", win_game)  # Makes you able to click enter
        label_check.configure(text="Level 5")  # Shows Level 5 at the top
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen

        def get_answer_last_screen():  # Defines get_answer_last_screen
            if entry_characters.get() == word:
                # Tells program that if the entry of characters = the correct/incorrect
                controller.show_frame("WinGameScreen")  # if answer is correct, WinGameScreen is shown
            else:
                controller.show_frame("IncorrectScreen")  # if answer is incorrect, IncorrectScreen is shown
        button_submit.configure(command=get_answer_last_screen)
        # Upon pressing button will change screen to either WinGameScreen or IncorrectScreen

    global button_next_screen  # Global variable
    button_next_screen = tk.Button(self, text="Progress to Next Level", bg="white", fg="black", height=4, width=20,
                                   # Changes colour/size
                                   command=next_level_two)
    # Uses the 'next_level_two' function

    def tutorial_show():  # Defines tutorial_show
        button_next_screen.configure(command=next_level_two)  # Uses the 'next_level_two' function
        controller.show_frame("Tutorial")  # Shows Tutorial screen

    def main_menu():  # Defines main_menu
        entUsername.focus_set()  # Makes it so the Username entry box is targeted
        button_next_screen.configure(command=next_level_two)  # Uses the 'next_level_two' function
        controller.show_frame("MainMenu")  # Shows MainMenu

    def win_game(event):  # Activated when user is on level 5
        controller.show_frame("WinGameScreen")  # Shows the WinGameScreen

    def difficulty_change():  # Defines difficulty_change
        entUsername.focus_set()  # Makes it so the Username entry box is targeted
        button_next_screen.configure(command=next_level_two)  # Uses the 'next_level_two' function
        controller.show_frame("Difficulty")  # Shows Difficulty screen

    button2 = tk.Button(self, text="Try a different difficulty", bg="white", fg="black", height=4, width=20,
                        # Changes colour/size
                        command=difficulty_change)  
    # Shows Difficulty screen and uses the 'difficulty_change' function
    button3 = tk.Button(self, text="Return to Main Menu", bg="white", fg="black", height=4, width=20,
                        # Changes colour/size
                        command=main_menu)
    # Shows Main Menu and uses the 'main_menu' function
    button_next_screen.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button_next_screen.config(font=("System", 10))  # Changes font/size
    button2.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button2.config(font=("System", 10))  # Changes font/size
    button3.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button3.config(font=("System", 10))  # Changes font/size

Class #15

class IncorrectScreen(tk.Frame):  # Class - Incorrect Screen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="red")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller
    # These labels are used to create blank spaces to centre my program
    lbl1 = tk.Label(self, text=" ", fg="white", bg="red")  # Changes colour of label
    lbl1.pack()  # Packs label wherever there's space
    lbl2 = tk.Label(self, text=" ", fg="white", bg="red")  # Changes colour of label
    lbl2.pack()  # Packs label wherever there's space
    lbl3 = tk.Label(self, text=" ", fg="white", bg="red")  # Changes colour of label
    lbl3.pack()  # Packs label wherever there's space
    lbl4 = tk.Label(self, text=" ", fg="white", bg="red")  # Changes colour of label
    lbl4.pack()  # Packs label wherever there's space

    label = tk.Label(self, text="INCORRECT!!:C", font=controller.title_font, bg="red")  # Changes font/colour
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally

    def retry_lose():  # Defines retry_lose
        pygame.mixer.Sound.play(button_click).set_volume(0.6)  # Sets the volume of 'button_click' function
        controller.show_frame("Difficulty")  # Shows Difficulty screen
        entUsername.focus_set()  # Makes it so the Username entry box is targeted

    global button_lose  # Global variable
    button_lose = tk.Button(self, text="Retry on a different difficulty", bg="white", fg="black", height=4,
                            # Changes size/colour
                            width=20, command=retry_lose)
    # Shows Difficulty screen and uses the 'retry_lose' function

    def tutorial_lose():  # Defines retry_lose
        pygame.mixer.Sound.play(button_click).set_volume(0.6)  # Sets the volume of 'button_click' function
        controller.show_frame("Tutorial")  # Shows Tutorial screen
        entUsername.focus_set()  # Makes it so the Username entry box is targeted

    global button_tutorial_lose  # Global variable
    button_tutorial_lose = tk.Button(self, text="Review How to Play", bg="white", fg="black", height=4, width=20,
                                     # Changes size/colour
                                     command=tutorial_lose)
    # Uses the Tutorial screen and uses the 'tutorial_lose' function
    global button_main_lose  # Global variable

    def main_lose():  # Defines main_lose
        pygame.mixer.Sound.play(button_click).set_volume(0.6)  # Sets the volume of 'button_click' function
        controller.show_frame("MainMenu")  # Shows MainMenu
        entUsername.focus_set()  # Makes it so the Username entry box is targeted

    button_main_lose = tk.Button(self, text="Return to Main Menu", bg="white", fg="black", height=4, width=20,
                                 # Changes size/colour
                                 command=main_lose)
    # Shows MainMenu and uses the 'main_lose' function
    button_lose.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button_lose.config(font=("System", 10))  # Changes font/size
    button_tutorial_lose.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button_tutorial_lose.config(font=("System", 10))  # Changes font/size
    button_main_lose.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button_main_lose.config(font=("System", 10))  # Changes font/size

Class #16

class Level2(tk.Frame):  # Class - Level2 Screen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller

    label = tk.Label(self, text="Remember these characters", font=controller.title_font, bg="#2699C3")
    # Changes font/colour

    global label_check  # Global variable
    label_check = tk.Label(self, text="Level 1", bg="#2699C3")  # Changes colour of label
    label_check.pack()  # Packs the label wherever there's space
    label.pack(side="top", fill="x", pady=10)  # How many pixels to pad widget, vertically/horizontally
    global label2_level2  # Global variable
    label2_level2 = tk.Label(self, height=4, width=15, text=word)  # Changes size, text=word
    label2_level2.config(font=("Courier", 64))  # Changes font/size
    label2_level2.pack()  # Packs the label wherever there's space

Class #17

class WinGameScreen(tk.Frame):  # Class - WinGameScreen
def __init__(self, parent, controller):  # Defines the window
    tk.Frame.__init__(self, parent, bg="#2699C3")  # Sets the background as that colour
    self.controller = controller  # Makes self.controller = controller
    # These labels are used to create blank spaces to centre my program

    background_image2 = tk.PhotoImage(file="videogame-well-done-4k-a-videogame-screen-with-the-text-well-done-8-bit-retro-style-4k_hv0skuloke_thumbnail-full05.png")
    background_label2 = tk.Label(self, image=background_image2)
    background_label2.place(x=0, y=0, relwidth=1, relheight=1)

    background_label2.image = background_image2

    lbl1 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl1.pack()  # Packs the label wherever there's space
    lbl2 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl2.pack()  # Packs the label wherever there's space
    lbl3 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl3.pack()  # Packs the label wherever there's space
    lbl4 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl4.pack()  # Packs the label wherever there's space
    lbl5 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl5.pack()  # Packs the label wherever there's space
    lbl6 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl6.pack()  # Packs the label wherever there's space
    lbl7 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl7.pack()  # Packs the label wherever there's space
    lbl8 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl8.pack()  # Packs the label wherever there's space
    lbl9 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl9.pack()  # Packs the label wherever there's space
    lbl10 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl10.pack()  # Packs the label wherever there's space
    lbl11 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl11.pack()  # Packs the label wherever there's space
    lbl12 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl12.pack()  # Packs the label wherever there's space
    lbl13 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl13.pack()  # Packs the label wherever there's space
    lbl14 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
    lbl14.pack()  # Packs the label wherever there's space

    def get_answer_last_screen():  # Defines get_answer_last_screen
        if entry_characters.get() == word:
            # Tells program that if the entry of characters = the correct/incorrect
            controller.show_frame("WinGameScreen")  # if answer is correct, WinGameScreen is shown
        else:
            controller.show_frame("IncorrectScreen")  # if answer is incorrect, IncorrectScreen is shown

    def get_answer():  # Defines get_answer
        if entry_characters.get() == word:  # Tells program that if the entry of characters = the correct/incorrect
            controller.show_frame("CorrectScreen")  # Show correct screen (if answer is correct)
        else:
            controller.show_frame("IncorrectScreen")  # Show incorrect screen (if answer is wrong)

    def get_answer2(event):  # Defines get_answer
        if entry_characters.get() == word:  # Tells program that if the entry of characters = the correct/incorrect
            controller.show_frame("CorrectScreen")  # Show correct screen (if answer is correct)
        else:
            controller.show_frame("IncorrectScreen")  # Show incorrect screen (if answer is wrong)

    def tutorial_show():  # Defines tutorial_show
        button_next_screen.configure(command=next_level_two)  # Uses the 'next_level_two' function
        controller.show_frame("Tutorial")  # Shows Tutorial screen

    def main_menu():  # Defines main_menu
        button_next_screen.configure(command=next_level_two)  # Uses the 'next_level_two' function
        controller.show_frame("MainMenu")  # Shows MainMenu

    def difficulty_change():  # Defines difficulty_change
        button_next_screen.configure(command=next_level_two)  # Uses the 'next_level_two' function
        controller.show_frame("Difficulty")  # Shows Difficulty screen

    def next_level_two():  # Defines next_level_two
        label_check.configure(text="Level 2")  # Shows Level 2 at the top
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen
        button_next_screen.configure(command=next_level_three)  # Shows Level 3 screen
        button_lose.configure(command=difficulty_change)  # Shows Difficulty screen
        button_tutorial_lose.configure(command=tutorial_show)  # Shows Tutorial screen
        button_main_lose.configure(command=main_menu)  # Shows Main Menu

    def next_level_three():  # Defines next_level_three
        label_check.configure(text="Level 3")  # Shows Level 3 at the top
        button_next_screen.configure(command=next_level_four)  # Shows Level 4 screen
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen

    def next_level_four():  # Defines next_level_four
        label_check.configure(text="Level 4")  # Shows Level 4 at the top
        button_next_screen.configure(command=next_level_five)  # Shows Level 5 screen
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen

    def next_level_five():  # Defines next_level_five
        label_check.configure(text="Level 5")
        button_next_screen.configure(command=get_answer_last_screen)  # Shows Level 5 at the top
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        x = (random_char(6))  # Displays 6 random characters
        global word  # Global variable
        word = x  # Word = x
        label2_level2.configure(text=word)  # Text=word
        entry_characters.delete(0, tk.END)  # Makes it so last entry's are deleted
        controller.show_frame("Level2")  # Shows Level 2 screen
        app.update()  # Updates program
        time.sleep(float(seconds_to_wait))  # Time program waits before changing to next screen
        controller.show_frame("EnterCharacterScreen")  # Shows EnterCharacterScreen

    def game_finished():  # Defines game_finished
        controller.show_frame("MainMenu"), return_to_main_menu()  
        # Shows MainMenu and uses the 'return_to_main_menu' function
        label_check.configure(text="Level 1")  # Shows Level 1 at the top of the screen
        label2_easy.configure(text=word)  # Configures the label so text=word for the corresponding difficulty
        label2_medium.configure(text=word)  # Configures the label so text=word for the corresponding difficulty
        label2_hard.configure(text=word)  # Configures the label so text=word for the corresponding difficulty
        label2_insane.configure(text=word)  # Configures the label so text=word for the corresponding difficulty
        button_submit.configure(command=get_answer)  # Uses the 'get_answer' function
        button_next_screen.configure(command=next_level_two)  # Uses the 'next_level_two function

    button1 = tk.Button(self, text="Return to Main Menu", bg="yellow", fg="black", height=2, width=20,
                        # Changes size/colour
                        command=game_finished)
    # Shows MainMenu and uses the 'game_finished' function
    button1.pack(pady=10)  # How many pixels to pad widget, vertically/horizontally
    button1.config(font=("System", 10))  # Changes font/size


 if __name__ == "__main__":  # If _name="main":
     app = SampleApp()  # Makes app = SampleApp
     app.mainloop()  # Loops the program so it can stay open
\$\endgroup\$
  • \$\begingroup\$ There also a class called Tutorial2, which is the second page of it, but due to the limit of characters i was unable to add it in! \$\endgroup\$ – Zachary Aug 9 '18 at 11:10
  • \$\begingroup\$ I also plan to add a leaderboards, a timer when each difficulty is selected, and an error message to appear if the user enters more than 6 characters or less than 6 (all of these im not sure how to do) \$\endgroup\$ – Zachary Aug 9 '18 at 11:11
  • \$\begingroup\$ Also if you plan to play this game, youll need to download the corresponding music/images but to test it id just advise you to remove them! \$\endgroup\$ – Zachary Aug 9 '18 at 11:12
  • 2
    \$\begingroup\$ Please fix your indentation, so that the classes actually contain their methods. Also enumerating your classes is not helpful at all. We all can count. \$\endgroup\$ – Richard Neumann Aug 9 '18 at 11:31
6
\$\begingroup\$

Most of your inline comments are useless

I see lots of comments like this:

def login_button():  # Defines login_button

That comment adds no information. It just adds visual "noise". I recommend removing all comments that simply state what the code does. Comments should explain why, and only if it's not obvious

Group your layout code separately from widget creation

In my experience, grouping all of your layout code together makes the code much easier to read, visualize, and maintain. For example, instead of this:

lbl1 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
lbl1.pack()  # Packs the label wherever there's space
lbl2 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
lbl2.pack()  # Packs the label wherever there's space
lbl3 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
lbl3.pack()  # Packs the label wherever there's space
lbl4 = tk.Label(self, text=" ", fg="white", bg="black")  # Changes colour of label
lbl4.pack()  # Packs the label wherever there's space

Do it like this:

lbl1 = tk.Label(self, text=" ", fg="white", bg="black")
lbl2 = tk.Label(self, text=" ", fg="white", bg="black")
lbl3 = tk.Label(self, text=" ", fg="white", bg="black")
lbl4 = tk.Label(self, text=" ", fg="white", bg="black")

lbl1.pack()
lbl2.pack()
lbl3.pack()
lbl4.pack()

Don't repeat identical code

There's one section that creates 14 identical labels, and you have two blocks of 14 identical lines of code. In this case it would be much more efficient to use a loop:

labels = []
for i in range(14):
    label = (tk.Label(self, text=" ", fg="white", bg="black")
    label.pack()
    labels.append(label)

This makes your intention much more clear. Whereas before I had to read every line (well, every other line) to try to determine if the labels are identical or not, with the loop it's immediately obvious that I'm creating fourteen identical labels.

Use explicit options to pack

I see a lot of code like this:

lbl1.pack()

I find it to be much easier to understand your code if you add explicit options rather than relying on defaults. This isn't true in all cases, but for things like grid and pack where the defaults aren't always obvious, I find it good to be explicit. It's also good to explicitly spell out the fill and expand options. That way, as a reviewer I can look at the code and know your intention. When you rely on defaults I'm left wondering if you intended to rely on the defaults or if you forgot to fully configure things.

lbl1.pack(side="top", fill="both", expand=False). 

Never use sleep in the main thread of a GUI

You should never use sleep because it does exactly that: it sleeps the entire application. That includes things like screen updates and the ability to respond to events.

Instead, move the code that you want to run after the sleep into a function, and call that function with after.

For example, instead of something like this:

   time.sleep(seconds_to_wait)  # Makes the program wait for however many seconds depending on difficulty
    controller.show_frame("EnterCharacterScreen")  # Displays the "EnterCharacterScreen"
    entry_characters.pack(fill=tk.X, padx=10, pady=10)  # How many pixels to pad widget, vertically/horizontally
    button_submit.pack(fill=tk.X, padx=80, pady=80, side=tk.BOTTOM)
    # How many pixels to pad widget, vertically/horizontally
    entry_characters.focus_set()  # Automatically clicks the entry box

... do something similar to this:

def callback():
    controller.show_frame("EnterCharacterScreen")
    entry_characters.pack(fill=tk.X, padx=10, pady=10)
    button_submit.pack(fill=tk.X, padx=80, pady=80, side=tk.BOTTOM)
    entry_characters.focus_set()  # Automatically clicks the entry box
self.after(seconds_to_wait*1000, callback)

Don't repeat code

Consider this block of code:

def play_music3():  # Defines play_music3
    pygame.mixer.music.load('Off Limits.wav')  # Loads 'Off Limits.wav') file
    pygame.mixer.music.play(-1)  # Makes the song play infinitely
    pygame.mixer.music.set_volume(0.8)  # Sets the volume (volume can be adjusted from 0-1)

def play_music4():  # Defines play_music4
    pygame.mixer.music.load('Pim Poy.wav')  # Loads 'Pim Poy.wav') file
    pygame.mixer.music.play(-1)  # Makes the song play infinitely
    pygame.mixer.music.set_volume(0.8)  # Sets the volume (volume can be adjusted from 0-1)

Those two blocks of code (and the others that follow) are virtually identical except for the .wav file to play and the number added to the function name. Sequential numbers on functions are a huge red flag. You should make this function generic, and have it accept a parameter to tell it which sound to play. The parameter can be an integer, but even better would be a string that represents the logical name of the sound (eg: "soundtrack 1", etc).

For example:

soundtracks = {
    1: 'Pim Poy.wav',
    2: 'Off Limits.wav',
}

def play_soundtrack(music_id):
    pygame.mixer.music.load(soundtracks[music_id]) 
    pygame.mixer.music.play(-1)  
    pygame.mixer.music.set_volume(0.8) 

With that, when you need to play a sound it would look like this, which I think is much easier to understand:

play_soundtrack(1)

If the sounds have different settings, you can incorporate all of that into your data structure. For example:

soundtracks = {
    1: {"file": "Pim Poy.wav", "volume": 0.8}
    ...
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.