Created
June 13, 2022 21:11
-
-
Save Spiruel/caddce0dcc0a609c804dfc4dfb20f608 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import streamlit as st | |
from datetime import datetime | |
import time | |
import random | |
import math | |
TIME_LIMIT = 30 #seconds | |
def answer(ans): | |
st.session_state['correct'] = ans | |
if ans == 'True': | |
#motivate quickfire answers with an exponential decay | |
score = (1 * math.exp(-0.05*(time.time()-st.session_state['time_now'])))*10 | |
st.session_state['score'] = max(1, score) | |
else: | |
#penalise wrong answers with a negative score | |
st.session_state['score'] = -10 | |
#update the score but don't prevent it from being negative | |
st.session_state['total_score'] += st.session_state['score'] | |
st.session_state['total_score'] = max(0, st.session_state['total_score']) | |
st.session_state['time_now'] = time.time() | |
st.session_state['count'] += 1 | |
def gen_question(): | |
#randomly choose two numbers in a range, alongside an operator | |
operators = ['+','-','//','*'] | |
a,b = random.randint(1,10), random.randint(1,10) | |
op = random.choice(operators) | |
#construct the question text and evaluate the calculation | |
ques = f"What is {a} {op} {b}?" | |
ans = eval(f"{a}{op}{b}") | |
#we want to avoid duplicate answer options, so use this inelegant solution | |
option2 = eval(f"{b}{op}{a}") | |
option3 = eval(f"{b-2}{op}{a+5}") | |
option4 = eval(f"{b}{op}{a}-{a}") | |
while option2 == ans: | |
option2 += 1 | |
while option3 == ans or option3 == option2: | |
option3 += 1 | |
while option4 == ans or option4 == option2 or option4 == option3: | |
option4 += 1 | |
return {'question': ques, | |
'options': { | |
ans: True, | |
option2: False, | |
option3: False, | |
option4: False | |
} | |
} | |
row = None | |
#initialise the session state if keys don't yet exist | |
if 'correct' not in st.session_state.keys(): | |
st.session_state['correct'] = None | |
if "quiz_active" not in st.session_state.keys(): | |
st.session_state["quiz_active"] = False | |
i,j,_ = st.columns([1,1,5]) | |
if i.button("Start quiz", key='start_quiz', disabled=st.session_state['quiz_active']): | |
st.session_state['quiz_active'] = True | |
st.session_state['total_score'] = 0 | |
st.session_state['count'] = 0 | |
#if 'time_start' not in st.session_state.keys(): | |
st.session_state['time_start'] = time.time() | |
st.session_state['time_now'] = time.time() | |
st.session_state['score'] = 0 | |
st.session_state['correct'] = None | |
st.experimental_rerun() | |
if j.button("End quiz and reset", key='reset', disabled=not st.session_state['quiz_active']): | |
st.session_state['total_score'] = 0 | |
st.session_state['count'] = 0 | |
st.session_state['correct'] = None | |
st.session_state['quiz_active'] = False | |
st.session_state['time_start'] = None | |
st.experimental_rerun() | |
if not st.session_state['quiz_active']: | |
st.write(f'\n Welcome to the quiz! You have {TIME_LIMIT} seconds to answer as many questions as you can.') | |
question_empty = st.empty() | |
d,e,f = st.columns([2,2,6]) | |
with d: | |
total_score_empty = st.empty() | |
with e: | |
st.write('') | |
answer_empty = st.empty() | |
if st.session_state['quiz_active']: | |
#check for time up upon page update | |
if time.time() - st.session_state['time_start'] > TIME_LIMIT: | |
st.info(f"Time's up! You scored a total of **{st.session_state['total_score']:.2f}** \ | |
and answered **{st.session_state['count']}** questions.") | |
else: | |
with question_empty: | |
with st.container(): | |
#get a newly generated question with answer options | |
row = gen_question() | |
st.markdown(f"Question {st.session_state['count']+1}: {row['question']}") | |
a,b,c = st.columns([2,2,6]) | |
options = list(row['options'].keys()) | |
random.shuffle(options) | |
#construct the answer buttons, and pass in whether the answer is correct or not in the args | |
a.button(f"{options[0]}", on_click=answer, args=(str(row['options'][options[0]]),)) | |
a.button(f"{options[1]}", on_click=answer, args=(str(row['options'][options[1]]),)) | |
b.button(f"{options[2]}", on_click=answer, args=(str(row['options'][options[2]]),)) | |
b.button(f"{options[3]}", on_click=answer, args=(str(row['options'][options[3]]),)) | |
if st.session_state['correct'] == 'True' and st.session_state['count'] > 0: | |
answer_empty.success(f"Question {st.session_state['count']} correct!") | |
elif st.session_state['correct'] == 'False' and st.session_state['count'] > 0: | |
answer_empty.error(f"Question {st.session_state['count']} incorrect!") | |
total_score_empty.metric('Total score', value=f"{st.session_state['total_score']:.2f}", delta=f"{st.session_state['score']:.2f}") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment