Home > OS >  Reaction Time Game counting rong (Python 3.10)
Reaction Time Game counting rong (Python 3.10)

Time:12-20

I'm making a reaction time game. description: Tkinter GUI, after random time a box with random color, size, font, place appears. openpyxl to save the game data if player wants to, threading for counting the seconds used, DateTime to put inside excel sheet for game data, random to choose place, size, font, color, text in box.

the intended game is that you get a box that appears after some time, you click, that box as fast as you can, it loops over that 3 times, when 3 times is finished you get a stats GUI with the time each of the 3 times, average time, save btn, play again btn.

error: the error is that the game counts wrong, if you try the game you will see that when the stats GUI come up all the time will be incremented by 0.01, example: time 1: 1.15 time 2: 1.16 time 3: 1.17

if someone could point out the error that would be amazing.

code:

from tkinter import *
from tkinter import messagebox
from time import sleep
import openpyxl
import datetime
import random
import threading

def run_game():
    root = Tk()
    root.title("Reaction Time Game")
    root.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/Reaction Time Game/icon.ico")
    root.geometry("1400x1000")
    root.configure(bg="orange")

    workbook = openpyxl.load_workbook(filename="time_data.xlsx")
    sheet = workbook.active

    time_used_list = []
    first_run = True

    def clicked3():
        global keep_counting
        keep_counting = False
        root.destroy()

        root2 = Tk()
        root2.title("Reaction Time Game Completed")
        root2.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/Reaction Time Game/icon.ico")
        root2.geometry("700x570")
        root2.configure(bg="lightblue")

        def save():
            current_datetime = datetime.datetime.now()
            current_datetime = current_datetime.strftime("%Y-%m-%d | %H:%M")

            place = sheet.max_row   1

            sheet[f"A{place}"] = round(time_used_list[0], 2)
            sheet[f"B{place}"] = round(time_used_list[1], 2)
            sheet[f"C{place}"] = round(time_used_list[2], 2)
            average = sum(time_used_list) / len(time_used_list)
            sheet[f"D{place}"] = round(average, 2)
            sheet[f"E{place}"] = current_datetime

            workbook.save(filename="time_data.xlsx")
            print("Saved time data")

        def run_another():
            root2.destroy()
            run_game()
        print("list of times:")
        for time in time_used_list:
            print(time)
        title_label = Label(root2, text="Results", font=("Arial", 20, "bold"), bg="orange")
        title_label.pack(padx=20, pady=20)
        time1_label = Label(root2, text=f"Time used 1: {round(time_used_list[0], 2)} seconds", font=("Arial", 20), bg="orange")
        time1_label.pack(padx=20, pady=20)
        time2_label = Label(root2, text=f"Time used 2: {round(time_used_list[1], 2)} seconds", font=("Arial", 20), bg="orange")
        time2_label.pack(padx=20, pady=20)
        time3_label = Label(root2, text=f"Time used 3: {round(time_used_list[2], 2)} seconds", font=("Arial", 20), bg="orange")
        time3_label.pack(padx=20, pady=20)
        average_time = sum(time_used_list) / len(time_used_list)
        average_label = Label(root2, text=f"Average Time Used: {round(average_time, 2)} seconds", font=("Arial", 20), bg="orange")
        average_label.pack(padx=20, pady=20)
        save_btn = Button(root2, text="Save", font=("Arial", 20), command=save, bg="orange")
        save_btn.pack(padx=20, pady=20)
        play_btn = Button(root2, text="Play Again", font=("Arial", 20), bg="orange", command=run_another)
        play_btn.pack(padx=20, pady=20)

        root2.mainloop()

    def clicked():
        global keep_counting, times_clicked, first_run
        keep_counting = False
        if times_clicked == 2:
            clicked3()
        else:
            times_clicked  = 1
            btn.destroy()
            print(first_run)
            print(times_clicked)
            first_run = False
            start(first_run)


    def time_thread():
        global time_used
        time_used = 0.00
        while keep_counting:
            sleep(0.01)
            time_used  = 0.01
        time_used_list.append(time_used)



    def start(first):
        global keep_counting, times_clicked, first_run
        if first:
            times_clicked = 0
            first_run = False

        color_list = ["red", "green", "yellow", "cyan", "white", "blue", "magenta"]
        random_color = random.choice(color_list)

        random_x = random.randint(100, 600)
        print(f"random_x = {random_x}")
        random_y = random.randint(100, 600)
        print(f"random_y = {random_y}")

        random_width = random.randint(5, 15)
        random_height = random.randint(5, 20)
        print(f"random_width = {random_width}, random_height = {random_height}")

        font_list = ["Helvetica", "Garamond", "Frutiger", "Bodoni", "Times", "Futura"]
        random_font = random.choice(font_list)
        random_font_size = random.randint(10, 18)
        print(f"Font = {random_font}, font_size = {random_font_size}")

        text_list = ["!", "?", "/", " ", "=", "<", ">", "%", "&", "(", ")", "-", "|", ";", ":", "[", "]", "{", "}", "^",
                     "@", "#"]
        random_text = random.choice(text_list)
        print(f"Random text = {random_text}")

        random_time = random.randint(3, 5)
        print(f"Random time = {random_time}")

        thread = threading.Thread(target=time_thread)
        keep_counting = True

        def btn_create():
            global btn
            btn = Button(root, text=random_text, font=(random_font, random_font_size), bg=random_color, width=random_width, command=clicked)
            btn.place(x=random_x, y=random_y)
            thread.start()

        time_wait = random_time * 1000
        root.after(time_wait, btn_create)

    start(first_run)

    root.mainloop()

run_game()

please help me.

CodePudding user response:

Your time_thread assumes that a sleep of 0.01 seconds always takes 0.01 seconds. That is patently false. Sleep merely guarantees you will wait for AT LEAST 0.01 seconds. On Windows, for example, the scheduler interval is about 0.016 seconds, so you can never sleep less than that. You can fix that by changing your timing thread to just snapshot the time before and after.

    def time_thread():
        start = time.time()
        while keep_counting:
            time.sleep(0.01)
        time_used_list.append(time.time()-start)

HOWEVER, even that has a huge flaw. The problem here is that, because of Python's interpreter lock, it's quite possible for keep_counting to be set False and then True again before the time_thread gets a chance to run, in which case it will just keep running. You end up with all three time_threads counting at once.

You don't need that loop. Just capture the starttime when you display the button, and capture the end time when it is clicked. Eliminate keep_counting and the time thread altogether. This eliminated the need for importing threading at all.

So:

def run_game():
    root = Tk()
    root.title("Reaction Time Game")
    root.geometry("1400x1000")
    root.configure(bg="orange")

    starttime = 0
    time_used_list = []
    first_run = True

    def clicked3():
        root.destroy()

        root2 = Tk()
...
    def clicked():
        global times_clicked, first_run
        time_used_list.append(time.time()-starttime)
        if times_clicked == 2:
            clicked3()
...
        random_time = random.randint(3, 5)
        print(f"Random time = {random_time}")

        def btn_create():
            global btn
            btn = Button(root, text=random_text, font=(random_font, random_font_size), bg=random_color, width=random_width, command=clicked)
            btn.place(x=random_x, y=random_y)
            starttime = time.time()

        time_wait = random_time * 1000
        root.after(time_wait, btn_create)

As a rule, don't count elapsed time using a thread. Just grab a start time and an end time and subtract.

  • Related