initial commit

This commit is contained in:
bePrivate
2023-07-19 16:10:48 +02:00
commit 24b00a5c77
2 changed files with 231 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
# Time^2
Time squared is a psychological test which measures
a subjet's attention span and concentration.
The goal is to click all 25 numbers in the grid in
ascending order as quickly as possible.
After finishing, the subject can see how they performed.
## Installation
_Prerequisites: python3, tkinter, matplotlib
Refer to their respective installation guides if you require help._
`git clone https://gitlab.com/bePrivate/time_squared`
`cd time_squared`
To start, type `python3 time_squared`.
Executable
+211
View File
@@ -0,0 +1,211 @@
#!/bin/python3
import tkinter as tk
import os as os
import argparse as ap
import time as ti
import random as ra
import matplotlib.pyplot as pl
from matplotlib.gridspec import GridSpec
class App(tk.Tk):
def __init__(self):
super().__init__()
# get cmd-line arguments
self.args = self.get_args()
# properties
self.resizable(False, False)
self.title("Time^2")
self.configure(bg="black")
self.measure_missclick = False
self.correct_number = 1 # the number that needs to be clicked next, aka the correct one
# width, height of canvas and window
self.w = 1000
self.h = 1000
self.screen_w = self.winfo_screenwidth()
self.screen_h = self.winfo_screenheight()
self.center_x = self.screen_w//2 - self.w//2
self.center_y = self.screen_h//2 - self.h//2
self.geometry(f"{self.w}x{self.h}+{self.center_x}+{self.center_y}")
# start screen (init phase 1)
self.btn_start = tk.Button(self, text="Start test", font=("Courier", 50))
self.btn_start.config(command=lambda btn=self.btn_start: self.init_phase_2(btn))
self.btn_start.pack(pady=450)
def init_phase_2(self, btn):
# buttons
self.taken = []
self.num_gone = 0
self.area = self.draw()
btn.destroy()
self.get_random()
# data needed for evaluation
self.data = {
"time_clicks": [],
"time_missclicks": [],
"time_test": 0,
"num_clicks": 0,
"num_missclicks": 0
}
self.start = ti.time()
self.start2 = ti.time()
self.start_entire_test = ti.time()
self.end = ti.time()
self.end_entire_test = ti.time()
def get_args(self):
p = ap.ArgumentParser(prog="Time^2")
p.add_argument("-d", "--debug", action="store_true", help="print debug messages")
return p.parse_args()
# debug print
def dp(self, payload: str):
if self.args.debug:
print(f"D: [{payload}]")
# drawing buttons on the screen
def draw(self) -> list[list]:
area = []
for i in range(5):
temp = []
for j in range(5):
button = tk.Button(self, width=50, height=5, font=("Courier", 40), text="", bg="#ffffff", fg="#000000")
button.config(command=lambda button=button, x=j*200, y=i*200, w=self.w//5, h=self.h//5: [self.button_callback(button, x, y, w, h)], activebackground="lightgray", activeforeground="black")
button.place(x=j*200, y=i*200, width=self.w//5, height=self.h//5)
self.dp(f"Creating a button => x: {j*200}, \ty: {i*200},\tw: {self.w//5},\th: {self.h//5}")
temp.append(button)
area.append(temp)
return area
# function for buttons to work
def button_callback(self, instance, x, y, w, h):
self.dp(f"Button clicked => {instance['text']}")
# only if the number is correct
if instance["text"] == str(self.correct_number):
self.data["num_clicks"] += 1
self.end = ti.time()
instance.destroy()
self.num_gone += 1
self.dp(f"Correct number was => {self.correct_number}")
self.correct_number += 1
if self.measure_missclick:
self.measure_missclick = False
self.data["time_missclicks"].append(self.end - self.start)
for i in range(5):
for j in range(5):
try:
if self.area[i][j]["bg"] == "#ff0000":
self.area[i][j].config(bg="#ffffff", fg="#000000", activebackground="lightgray", activeforeground="#000000")
self.area[i][j].place()
except:
pass
self.data["time_clicks"].append(self.end - self.start2)
self.start = ti.time()
self.start2 = ti.time()
else:
if instance["bg"] != "#ff0000":
self.measure_missclick = True
self.start = ti.time()
self.data["num_clicks"] += 1
self.data["num_missclicks"] += 1
self.dp(f"Number of missclicks => {self.data['num_missclicks']}")
instance.config(bg="#ff0000", fg="#ffffff", activebackground="darkred", activeforeground="#ffffff")
instance.place(x=x, y=y, width=w, height=h)
# check for test end
if self.num_gone == 25:
self.destroy()
self.end_entire_test = ti.time()
self.data["time_test"] = self.end_entire_test - self.start_entire_test
self.show_data()
self.dp("Data => ")
for key in self.data:
if type(self.data[key]) == float or type(self.data[key]) == int:
self.dp(" "+key+" => "+
"\n "+str(self.data[key]))
if type(self.data[key]) == list:
self.dp(" "+key+" => "+
"".join(["\n "+str(i) for i in self.data[key]]))
# returns a random number that can be used as a text in a new button
def get_random(self) -> str:
for i in range(5):
for j in range(5):
r = ra.randint(1, 25)
while r in self.taken:
r = ra.randint(1, 25)
self.taken.append(r)
self.area[i][j]["text"] = str(r)
def show_data(self):
if len(self.data["time_clicks"]) != 0:
time_click_avg = sum(self.data["time_clicks"])/len(self.data["time_clicks"])
else:
time_click_avg = 0
if self.data["time_clicks"] != []:
time_click_longest = max(self.data["time_clicks"])
time_click_shortest = min(self.data["time_clicks"])
else:
time_click_longest = 0
time_click_shortest = 0
if len(self.data["time_missclicks"]) != 0:
time_missclick_avg = sum(self.data["time_missclicks"])/len(self.data["time_missclicks"])
else:
time_missclick_avg = 0
if self.data["time_missclicks"] != []:
time_missclick_longest = max(self.data["time_missclicks"])
time_missclick_shortest = min(self.data["time_missclicks"])
else:
time_missclick_longest = 0
time_missclick_shortest = 0
pl.rcParams["toolbar"] = "None"
ax1 = pl.subplot(2, 1, 1)
ax2 = pl.subplot(2, 1, 2)
ax1.set_title("Time between clicks on correct numbers", loc="left")
ax1.plot(self.data["time_clicks"], marker="o")
ax2.set_title("Time between missclicks and corrections", loc="left")
ax2.plot(self.data["time_missclicks"], "o")
pl.subplots_adjust(hspace=1)
tb = pl.table( cellText=[
[round(time_click_avg, 2), round(time_missclick_avg, 2), ""],
[round(time_click_longest, 2), round(time_missclick_longest, 2), ""],
[round(time_click_shortest, 2), round(time_missclick_shortest, 2), ""],
["", self.data["num_missclicks"], ""],
["", "", round(self.data["time_test"], 2)]],
rowLabels=
["Average time", "Longest time", "Shortest time", "Count", "Time taken"],
colLabels=
["Between clicks", "Between missclicks and corrections", "To complete the test"],
colColours=
["lightgray", "lightgray", "lightgray"],
rowColours=
["lightgray", "lightgray", "lightgray", "lightgray", "lightgray"],
loc=
"top"
)
tb.set_fontsize(120)
pl.show()
if __name__ == "__main__":
app = App()
app.mainloop()