from tkinter import * from functools import partial # To prevent unwanted windows 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) self.start_frame.grid() # strings for labels intro_string = ("In each round you will be invited to choose a colour. your goal is " "to beat the target score and win the round (and keep your points)") # 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 = [ ["Colour Quest", ("Arial", "16", "bold"), None], [intro_string, ("Arial", "12", "bold"), None], [choose_string, ("Arial", "12", "bold"), "#009900"] ] # 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) 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) 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="#0057D8", 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 = 5 self.to_play(rounds_wanted) def to_play(self, num_rounds): """ Invokes game GUI and takes across number of rounds to be played """ Play(num_rounds) # hide root window (ie: hide rounds choice window). root.withdraw() class Play: """ Interface for playing the Colour Quest Game """ def __init__(self, how_many): self.rounds_won = IntVar() # lists for stats component # highest score test data # self.all_scores_list = [20, 20, 20, 16, 19] # self.all_high_score_list = [20, 20, 20, 16, 19] # self.rounds_won.set(5) # lowest score test data # self.all_scores_list = [0, 0, 0, 0, 0] # self.all_high_score_list = [20, 20, 20, 16, 19] # self.rounds_won(0) # 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="Hints", fg="#FFFFFF", bg="#FF8000", 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] high_scores = all_stats_info[2] # 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) self.stats_frame.grid() # math to populate stats dialogue rounds_played = len(user_scores) success_rate = rounds_won / rounds_played * 100 total_score = sum(user_scores) max_possible = sum(high_scores) best_score = user_scores[-1] average_score = total_score / rounds_played # 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}" max_possible_string = f"Maximum Possible Score: {max_possible}" best_score_string = f"Best Score: {best_score}" # custom comment text and formatting if total_score == max_possible: comment_string = ("Amazing! You got the highest possible score!") comment_colour = "#D5E8D4" elif total_score == 0: comment_string = ("Oops - You lose every round! You might want to look at the hints") comment_colour = "#F8CECC" else: comment_string = "" comment_colour = "#F0F0F0" average_score_string = f"Average Score: {average_score:.0f}\n" heading_font = ("Arial", "16", "bold") normal_font = ("Arial", "14") comment_font = ("Arial", "13") # Label list (text | font | 'Sticky') all_stats_strings = [ ["Statistics", heading_font, ""], [success_string, normal_font, "W"], [total_score_string, normal_font, "W"], [max_possible_string, normal_font, "W"], [comment_string, comment_font, "W"], ["\nRound Stats", heading_font, ""], [best_score_string, normal_font, "W"], [average_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) self.stats_label.grid(row=count, sticky=item[2], padx=10) stats_label_ref_list.append(self.stats_label) # configure comment label background (for all won / all lost) stats_comment_label = stats_label_ref_list[4] stats_comment_label.config(bg=comment_colour) self.dismiss_button = Button(self.stats_frame, font=("Arial", "16", "bold"), text="Dismiss", bg="#333333", 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("Colour Quest") StartGame() root.mainloop()