Skip to content

Commit 425e415

Browse files
author
rajfly
committedApr 4, 2023
first commit
1 parent 68c4a73 commit 425e415

File tree

3 files changed

+183
-0
lines changed

3 files changed

+183
-0
lines changed
 

‎README.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,15 @@
11
# immediate-feedback-quiz
22
A simple python based application designed to give immediate feedback to participants for a quiz on army ants.
3+
4+
### Install and run
5+
```bash
6+
# install
7+
conda create -y -n quiz python=3.9 && conda activate quiz
8+
pip install pandas
9+
10+
# run for each participant
11+
python quiz.py
12+
13+
# run after everyone has taken the quiz to combine results from all participant csv files
14+
pytnon combine.py
15+
```

‎combine.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import os
2+
import pandas as pd
3+
4+
if __name__ == "__main__":
5+
path = os.path.join(os.getcwd(), 'results')
6+
results = []
7+
for root, dirs, files in os.walk(path):
8+
for f in files:
9+
df = pd.read_csv(os.path.join(root, f), index_col=0)
10+
results.append(df)
11+
df = pd.concat(results, ignore_index=True)
12+
df.to_csv(os.path.join(path, 'combined.csv'), index=False)

‎quiz.py

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import tkinter as tk
2+
import pandas as pd
3+
import uuid
4+
import os
5+
6+
def eval():
7+
global ix, question, v, radio_buttons, next_button, response
8+
global selected, score
9+
10+
answer = v.get()
11+
selected.append(answer)
12+
question.destroy()
13+
next_button.destroy()
14+
for button in radio_buttons: button.destroy()
15+
16+
if answer == ANSWERS[ix]:
17+
root.configure(bg='#028A0F')
18+
response = tk.Label(root, text='You got it correct, well done!', font=font, bg='#028A0F')
19+
response.grid(row=2)
20+
next_button = tk.Button(root, text='Next', font=font, height=5, width=15, command=next)
21+
next_button.grid(row=len(OPTIONS[ix])+1)
22+
score += 1
23+
24+
else:
25+
root.configure(bg='#B90E0A')
26+
response = tk.Label(root, text='You got it wrong, better luck next time!', font=font, bg='#B90E0A')
27+
response.grid(row=2)
28+
next_button = tk.Button(root, text='Next', font=font, height=5, width=15, command=next)
29+
next_button.grid(row=len(OPTIONS[ix])+1)
30+
31+
def next():
32+
global ix, question, v, radio_buttons, next_button, response
33+
global name, email, score, selected
34+
35+
root.configure(bg=default)
36+
response.destroy()
37+
next_button.destroy()
38+
ix += 1
39+
if ix < len(QUESTIONS):
40+
question = tk.Label(root, text=QUESTIONS[ix], font=font, wraplength=1000, justify='center')
41+
question.grid(row=0)
42+
v = tk.IntVar()
43+
radio_buttons = []
44+
for i, j in enumerate(OPTIONS[ix]):
45+
radio_button = tk.Radiobutton(root, text=j, variable=v, value=i, font=font, wraplength=1000, justify='center')
46+
radio_button.grid(row=i+1)
47+
radio_buttons.append(radio_button)
48+
next_button = tk.Button(root, text='Next', font=font, height=5, width=15, command=eval)
49+
next_button.grid(row=len(OPTIONS[ix])+1)
50+
else:
51+
out = {'Email Address': [email], 'Score': [score], 'Name': [name], 'Group': ['C']}
52+
for i, j in enumerate(selected):
53+
out[QUESTIONS[i]] = [OPTIONS[i][selected[i]]]
54+
df = pd.DataFrame.from_dict(out)
55+
if not os.path.exists(os.path.join(os.getcwd(), 'results')):
56+
os.makedirs(os.path.join(os.getcwd(), 'results'))
57+
df.to_csv(os.path.join(os.getcwd(), 'results', f'{uuid.uuid4()}.csv'))
58+
root.destroy()
59+
60+
def start():
61+
global name, email
62+
global greeting, start_button
63+
global name_label, name_entry
64+
global email_label, email_entry
65+
global ix, question, v, radio_buttons, next_button
66+
67+
# store entries and destroy
68+
name = name_entry.get()
69+
email = email_entry.get()
70+
greeting.destroy()
71+
name_label.destroy()
72+
name_entry.destroy()
73+
email_label.destroy()
74+
email_entry.destroy()
75+
start_button.destroy()
76+
77+
# start qn index
78+
ix = 0
79+
question = tk.Label(root, text=QUESTIONS[ix], font=font, wraplength=1000, justify='center')
80+
question.grid(row=0)
81+
82+
v = tk.IntVar()
83+
radio_buttons = []
84+
for i, j in enumerate(OPTIONS[ix]):
85+
radio_button = tk.Radiobutton(root, text=j, variable=v, value=i, font=font, wraplength=1000, justify='center')
86+
radio_button.grid(row=i+1)
87+
radio_buttons.append(radio_button)
88+
89+
next_button = tk.Button(root, text='Next', font=font, height=5, width=15, command=eval)
90+
next_button.grid(row=len(OPTIONS[ix])+1)
91+
92+
root.columnconfigure((0), weight=1)
93+
root.rowconfigure(list(range(1,len(OPTIONS[ix])+1)), weight=1)
94+
root.rowconfigure((0,len(OPTIONS[ix])+1), weight=3)
95+
96+
if __name__ == '__main__':
97+
# globals
98+
QUESTIONS = ['What is the moral of the video?',
99+
'How long ago did Ants originate?',
100+
'When two army ant colonies encounter each other, which of the following happens?',
101+
'Which of the following is true?',
102+
'What is the main reason army ants are so feared?',
103+
'How many different species are there in army ant groups?',
104+
'What will leafcutter ants do first to defend against army ants?',
105+
'What will leafcutter ants do second to defend against army ants?',
106+
'Army ant species Nomamyrmex Esenbeckii is the only known species that can successfully attack a mature colony of leafcutters.',
107+
'The war of ants only happens among different species.']
108+
OPTIONS = [['Some groups just don\'t get along', 'Don’t be greedy, be content with what you have', 'Death is as much part of life, as life itself', 'Where there is a will, there is a way'],
109+
['160 billion years ago', '160 million years ago', '6 million years ago', '6 thousand years ago'],
110+
['The colonies fight, to the death', 'The colonies pass through each other or just move away from each other', 'The colonies merge together', 'None of the above'],
111+
['Army ants are so deadly that other ant species had to specialize to survive their presence', 'Many species stand their ground and fight instead of evacuating when seeing an army ant scout', 'Some ants have big square heads built to crush army ants', 'None of the above'],
112+
['The fact that they come in extremely large numbers', 'Their painful bites', 'Their venomous stingers', 'Their ability to burrow'],
113+
['About 2 trillion species', 'About 2 billion species', 'About 2 million species', 'About 200 species'],
114+
['Kick them', 'Lock on them and try to cut through their heads', 'Block entrances to their nest with their square heads', 'Sting them to death, in a mob'],
115+
['They seal of entrances to their nest', 'They run away', 'They rush in and surround their eggs', 'None of the above'],
116+
['True', 'False'],
117+
['True', 'False']]
118+
ANSWERS = [0,1,1,0,0,3,1,0,0,1]
119+
name = None
120+
email = None
121+
v = None
122+
ix = None
123+
question = None
124+
radio_buttons = None
125+
next_button = None
126+
response = None
127+
128+
score = 0
129+
selected = []
130+
131+
font = ('Menlo', 30)
132+
133+
root = tk.Tk()
134+
root.geometry('1450x1000')
135+
root.title('Quiz')
136+
default = root.cget('bg')
137+
138+
greeting = tk.Label(root, text='Enter your email and name and start the quiz, good luck!', font=font)
139+
greeting.grid(row=0)
140+
141+
name_label = tk.Label(root, text='Name', font=font)
142+
name_label.grid(row=1)
143+
name_entry = tk.Entry(root)
144+
name_entry.grid(row=2)
145+
146+
email_label = tk.Label(root, text='Email', font=font)
147+
email_label.grid(row=3)
148+
email_entry = tk.Entry(root)
149+
email_entry.grid(row=4)
150+
151+
start_button = tk.Button(root, text='Start', font=font, height=5, width=15, command=start)
152+
start_button.grid(row=5)
153+
154+
root.columnconfigure((0), weight=1)
155+
root.rowconfigure((1,2,3,4), weight=1)
156+
root.rowconfigure((0,5), weight=3)
157+
158+
root.mainloop()

0 commit comments

Comments
 (0)
Please sign in to comment.