from tkinter import * from functools import partial class StartGame: """ Initial Game interface (asks users how many rounds they would like to play) """ def __init__(self): """ Gets number of rounds from user """ self.start_frame = Frame(padx=10, pady=10, bg="#0C0C0C") self.start_frame.grid() # strings for labels intro_string = ("Welcome to Lyric Guessing! In each round you will be given a song lyric " "and you need to select the missing lyric. Good Luck!") # choose string = "Oops - Please choose a whole number more than zero." choose_string = "How many rounds do you want to play" # List of labels to be made (text | font | fg) start_labels_list = [ ["Lyric Guessing", ("Arial", "16", "bold"), "#F7EFFB"], [intro_string, ("Arial", "12", "bold"), "#F7EFFB"], [choose_string, ("Arial", "12", "bold"), "#F7EFFB"] ] # create labels and add them to the reference list... start_label_ref = [] for count, item in enumerate(start_labels_list): make_label = Label(self.start_frame, text=item[0], font=item[1], fg=item[2], wraplength=350, justify="left", pady=10, padx=20, bg="#0C0C0C") make_label.grid(row=count) start_label_ref.append(make_label) # extract choice label so that it can be changed to an error message if necessary self.choose_label = start_label_ref[2] # frame so that entry box and button can be in the same row self.entry_area_frame = Frame(self.start_frame, bg="#0C0C0C") self.entry_area_frame.grid(row=3) self.num_rounds_entry = Entry(self.entry_area_frame, font=("Arial", "20", "bold"), width=10,) self.num_rounds_entry.grid(row=0, column=0, padx=10, pady=10) # create play button self.play_button = Button(self.entry_area_frame, font=("Arial", "16", "bold"), fg="#FFFFFF", bg="#7D28A4", text="Play", width=10, command=self.check_rounds) self.play_button.grid(row=0, column=1) def check_rounds(self): """ Checks users have entered 1 or more rounds """ rounds_wanted = self.num_rounds_entry.get() # Reset label and entry box (for when users come back to the home screen) self.choose_label.config(fg="#009900", font=("Arial", "12", "bold")) self.num_rounds_entry.config(bg="#0C0C0C") error = "Oops - Please choose a whole number more than zero" has_errors = "no" # checks that amount to be converted is a number above absolute zero try: rounds_wanted = int(rounds_wanted) if rounds_wanted > 0: # invoke Play class (and take across number of rounds) self.num_rounds_entry.delete(0, END) self.choose_label.config(text="How many rounds do you want to play?") Play(rounds_wanted) # Hide root window (ie: hide rounds choice window) root.withdraw() else: has_errors = "yes" except ValueError: has_errors = "yes" # display the error if necessary if has_errors == "yes": self.choose_label.config(text=error, fg="#990099", font=("Arial", "10", "bold")) self.num_rounds_entry.config(bg="#F4CCCC") self.num_rounds_entry.delete(0, END) class Play: """ Interface for playing the Colour Quest Game """ def __init__(self, how_many): self.rounds_won = IntVar() # random score test data self.all_scores_list = [0, 15, 16, 0, 16] self.all_high_score_list = [20, 19, 18, 20, 20] self.rounds_won.set(3) self.play_box = Toplevel() self.game_frame = Frame(self.play_box) self.game_frame.grid(pady=10, padx=10) self.game_heading_label = Label(self.game_frame, text=f"Round 0 of {how_many}", font=("Arial", "16", "bold")) self.game_heading_label.grid(row=0) self.to_stats_button = Button(self.game_frame, font=("Arial", "14", "bold"), text="Stats", fg="#FFFFFF", bg="#7D28A4", width="10", command=self.to_stats, pady=10, padx=10) self.to_stats_button.grid(row=1) def to_stats(self): """ displays hints for playing game """ # important: retrieve number of rounds # won as a number (rather than the self container rounds_won = self.rounds_won.get() stats_bundle = [rounds_won, self.all_scores_list, self.all_high_score_list] Stats(self, stats_bundle) class Stats: """ Temperature conversion tool """ def __init__(self, partner, all_stats_info): # extract information from the master list rounds_won = all_stats_info[0] user_scores = all_stats_info[1] # sort user score to find high score... user_scores.sort() # setup dialogue box self.stats_box = Toplevel() # disable stats button partner.to_stats_button.config(state=DISABLED) # if user press cross at top, close stats and 'releases' stats button self.stats_box.protocol('WM_DELETE_WINDOW', partial(self.close_stats, partner)) self.stats_frame = Frame(self.stats_box, width=300, height=200, bg="#F7EFFD") self.stats_frame.grid() # math to populate stats dialogue rounds_played = len(user_scores) with open("stats_list.txt", "a") as file: file.write(f"{sum(user_scores)}\n") with open("stats_list.txt", "r") as file: past_scores = [int(line.strip()) for line in file.readlines() if line.strip() != ''] with open('stats_list.txt', 'r') as file: contents = file.read() line_count = contents.count('\n') if line_count > 0: lines_for_average = line_count else: lines_for_average = 1 success_rate = rounds_won / rounds_played * 100 total_score = sum(user_scores) total_for_average = sum(past_scores) print(total_for_average) average_score = total_for_average / lines_for_average high_score = max(past_scores) # strings for start labels success_string = (f"Success Rate: {rounds_won} / {rounds_played}" f"({success_rate:.0f}%)") total_score_string = f"Total Score: {total_score}" average_score_string = f"Average Score: {average_score:.0f}\n" high_score_string = f"Overall High Score: {high_score}\n" heading_font = ("Arial", "16", "bold") normal_font = ("Arial", "14") # Label list (text | font | 'Sticky') all_stats_strings = [ ["Round Stats", heading_font, ""], [success_string, normal_font, "W"], [total_score_string, normal_font, "W"], ["\nAll Stats", heading_font, ""], [average_score_string, normal_font, "W"], [high_score_string, normal_font, "W"] ] stats_label_ref_list = [] for count, item in enumerate(all_stats_strings): self.stats_label = Label(self. stats_frame, text=item[0], font=item[1], anchor="w", justify="left", padx=30, pady=5, bg="#F7EFFD") self.stats_label.grid(row=count, sticky=item[2], padx=10) stats_label_ref_list.append(self.stats_label) self.dismiss_button = Button(self.stats_frame, font=("Arial", "16", "bold"), text="Dismiss", bg="#7D28A4", fg="#FFFFFF", width=20, command=partial(self.close_stats, partner)) self.dismiss_button.grid(row=8, padx=10, pady=10) def close_stats(self, partner): partner.to_stats_button.config(state=NORMAL) self.stats_box.destroy() # main routine if __name__ == "__main__": root = Tk() root.title("Lyric Guessing") StartGame() root.mainloop()