Skip to content

Instantly share code, notes, and snippets.

@Spiruel
Created June 13, 2022 21:11
Show Gist options
  • Save Spiruel/caddce0dcc0a609c804dfc4dfb20f608 to your computer and use it in GitHub Desktop.
Save Spiruel/caddce0dcc0a609c804dfc4dfb20f608 to your computer and use it in GitHub Desktop.
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