Quiz
Take a multiple-choice quiz, get a score, review the questions you missed and retake only those until none are left; every attempt is kept in a score history - from a text menu.
Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.
About
A multiple-choice quiz of eight questions. Taking the quiz gives a score and a percentage; the questions you got wrong can then be reviewed - your answer next to the right one - and retaken on their own, again and again, until none are left. Every scored attempt goes into a score history, which is kept while the program runs.
main.eml- the menu, the score report, the review of mistakes, and the score historybank.eml- the questions: each has a number, the question, four options A to D, and the right letterquiz.eml- asking a question, reading the answer, marking an attempt, and the percentage
An attempt asks its questions in order and keeps the ones answered wrongly, with the answer given. A retake asks only the last attempt's mistakes, and its own mistakes replace them, so a question answered right drops out. Typing q at an answer stops the attempt: a stopped attempt is not scored, goes into no history, and leaves the mistakes as they were. The percentage is worked out in whole numbers and rounded half up (7/8 shows as 88%).
What is checked: an answer is one letter, A to D in either case, or q; anything else asks the same question again.
Sessions: sessions/basic.in takes the quiz with two mistakes, reviews them, retakes them (one right, one wrong again), reviews and retakes the one that is left until there are none, and shows the three scores; sessions/bad-input.in types an unknown choice, asks for a review, a retake and the scores before any quiz, types a letter that is not an option, nothing, two letters and a lower-case answer, stops a quiz (it is not scored), then answers in lower case with one mistake, stops the retake, and retakes until nothing is left to review or retake.
Built on the verified corpus case simple-quiz-grader (answers marked against the right ones, with a score and a percentage).
Recorded sessions
What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.
bad-input
interpreter: byte-equal
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 9
Pick a number from 1 to 5.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 2
Take the quiz first.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 3
Take the quiz first.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 4
-- scores --
(no attempts yet)
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 1
Q1. What gas do plants take in for photosynthesis?
A) Oxygen
B) Carbon dioxide
C) Nitrogen
D) Helium
answer> e
Answer with A, B, C or D (or q to stop).
answer>
Answer with A, B, C or D (or q to stop).
answer> ab
Answer with A, B, C or D (or q to stop).
answer> b
Right.
Q2. How many bones are in the adult human body?
A) 106
B) 206
C) 306
D) 406
answer> q
Quiz stopped; not scored.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 4
-- scores --
(no attempts yet)
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 1
Q1. What gas do plants take in for photosynthesis?
A) Oxygen
B) Carbon dioxide
C) Nitrogen
D) Helium
answer> b
Right.
Q2. How many bones are in the adult human body?
A) 106
B) 206
C) 306
D) 406
answer> b
Right.
Q3. What is the chemical symbol for gold?
A) Ag
B) Gd
C) Au
D) Go
answer> c
Right.
Q4. Which planet is closest to the Sun?
A) Venus
B) Mars
C) Mercury
D) Earth
answer> c
Right.
Q5. What is the largest ocean on Earth?
A) Atlantic
B) Indian
C) Arctic
D) Pacific
answer> d
Right.
Q6. Which river flows through Cairo?
A) Nile
B) Amazon
C) Danube
D) Ganges
answer> a
Right.
Q7. On which continent is the Sahara desert?
A) Asia
B) Africa
C) Australia
D) South America
answer> b
Right.
Q8. What is the capital of Canada?
A) Toronto
B) Vancouver
C) Ottawa
D) Montreal
answer> a
Wrong - it is C) Ottawa.
Score: 7/8 (88%).
1 to review.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 3
Q8. What is the capital of Canada?
A) Toronto
B) Vancouver
C) Ottawa
D) Montreal
answer> x
Answer with A, B, C or D (or q to stop).
answer> q
Retake stopped; not scored.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 4
-- scores --
1) quiz 7/8 88%
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 3
Q8. What is the capital of Canada?
A) Toronto
B) Vancouver
C) Ottawa
D) Montreal
answer> c
Right.
Score: 1/1 (100%).
No mistakes - well done.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 3
No mistakes to retake.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 2
No mistakes to review.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 4
-- scores --
1) quiz 7/8 88%
2) retake 1/1 100%
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 5
Bye.
What was typed (30 lines)
9
2
3
4
1
e
ab
b
q
4
1
b
b
c
c
d
a
b
a
3
x
q
4
3
c
3
2
4
5
basic
interpreter: byte-equal
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 1
Q1. What gas do plants take in for photosynthesis?
A) Oxygen
B) Carbon dioxide
C) Nitrogen
D) Helium
answer> B
Right.
Q2. How many bones are in the adult human body?
A) 106
B) 206
C) 306
D) 406
answer> B
Right.
Q3. What is the chemical symbol for gold?
A) Ag
B) Gd
C) Au
D) Go
answer> A
Wrong - it is C) Au.
Q4. Which planet is closest to the Sun?
A) Venus
B) Mars
C) Mercury
D) Earth
answer> C
Right.
Q5. What is the largest ocean on Earth?
A) Atlantic
B) Indian
C) Arctic
D) Pacific
answer> D
Right.
Q6. Which river flows through Cairo?
A) Nile
B) Amazon
C) Danube
D) Ganges
answer> A
Right.
Q7. On which continent is the Sahara desert?
A) Asia
B) Africa
C) Australia
D) South America
answer> A
Wrong - it is B) Africa.
Q8. What is the capital of Canada?
A) Toronto
B) Vancouver
C) Ottawa
D) Montreal
answer> C
Right.
Score: 6/8 (75%).
2 to review.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 2
Q3. What is the chemical symbol for gold?
you said A) Ag; it is C) Au.
Q7. On which continent is the Sahara desert?
you said A) Asia; it is B) Africa.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 3
Q3. What is the chemical symbol for gold?
A) Ag
B) Gd
C) Au
D) Go
answer> C
Right.
Q7. On which continent is the Sahara desert?
A) Asia
B) Africa
C) Australia
D) South America
answer> C
Wrong - it is B) Africa.
Score: 1/2 (50%).
1 to review.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 2
Q7. On which continent is the Sahara desert?
you said C) Australia; it is B) Africa.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 3
Q7. On which continent is the Sahara desert?
A) Asia
B) Africa
C) Australia
D) South America
answer> B
Right.
Score: 1/1 (100%).
No mistakes - well done.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 2
No mistakes to review.
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 4
-- scores --
1) quiz 6/8 75%
2) retake 1/2 50%
3) retake 1/1 100%
== Quiz ==
1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit
choice> 5
Bye.
What was typed (19 lines)
1
B
B
A
C
D
A
A
C
2
3
C
C
2
3
B
2
4
5
Modules
The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.
main.eml(entry)
eml# P010 quiz: take the quiz, review the questions you missed, and retake only
# those until none are left. Every scored attempt goes into the score
# history, which lives while the program runs.
import bank
import quiz
def report(score, total, mistakes):
("Score: " + str(score) + "/" + str(total) + " (" + str(quiz.percent(score, total)) + "%).") ^0
if len(mistakes) == 0:
"No mistakes - well done." ^0
else:
(str(len(mistakes)) + " to review.") ^0
def review(mistakes):
for m in mistakes:
m[0] => q
"" ^0
("Q" + str(q[0]) + ". " + q[1]) ^0
(" you said " + m[1] + ") " + bank.option_text(q, m[1]) + "; it is " + q[3] + ") " + bank.option_text(q, q[3]) + ".") ^0
# [kind, score, total] for every scored attempt
[] => history
# None until the quiz has been taken; then the last attempt's mistakes
None => mistakes
True => running
while running:
"" ^0
"== Quiz ==" ^0
"1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit" ^0
quiz.trim(input("choice> ")) => choice
if choice == "1":
quiz.attempt(bank.questions) => r
if r == None:
"Quiz stopped; not scored." ^0
else:
report(r[0], len(bank.questions), r[1])
history + [["quiz", r[0], len(bank.questions)]] => history
r[1] => mistakes
elif choice == "2":
if mistakes == None:
"Take the quiz first." ^0
elif len(mistakes) == 0:
"No mistakes to review." ^0
else:
review(mistakes)
elif choice == "3":
if mistakes == None:
"Take the quiz first." ^0
elif len(mistakes) == 0:
"No mistakes to retake." ^0
else:
[m[0] for m in mistakes] => again
quiz.attempt(again) => r
if r == None:
"Retake stopped; not scored." ^0
else:
report(r[0], len(again), r[1])
history + [["retake", r[0], len(again)]] => history
r[1] => mistakes
elif choice == "4":
"" ^0
"-- scores --" ^0
if len(history) == 0:
" (no attempts yet)" ^0
0 => n
for h in history:
n + 1 => n
(" " + str(n) + ") " + ("%-7s" % h[0]) + ("%5s" % (str(h[1]) + "/" + str(h[2]))) + ("%6s" % (str(quiz.percent(h[1], h[2])) + "%"))) ^0
elif choice == "5":
False => running
else:
"Pick a number from 1 to 5." ^0
"Bye." ^0
Python projection (main.py)
import bank
import quiz
def report(score, total, mistakes):
print("Score: " + str(score) + "/" + str(total) + " (" + str(quiz.percent(score, total)) + "%).")
if len(mistakes) == 0:
print("No mistakes - well done.")
else:
print(str(len(mistakes)) + " to review.")
def review(mistakes):
for m in mistakes:
q = m[0]
print("")
print("Q" + str(q[0]) + ". " + q[1])
print(" you said " + m[1] + ") " + bank.option_text(q, m[1]) + "; it is " + q[3] + ") " + bank.option_text(q, q[3]) + ".")
history = []
mistakes = None
running = True
while running:
print("")
print("== Quiz ==")
print("1) take the quiz 2) review mistakes 3) retake mistakes 4) scores 5) quit")
choice = quiz.trim(input("choice> "))
if choice == "1":
r = quiz.attempt(bank.questions)
if r == None:
print("Quiz stopped; not scored.")
else:
report(r[0], len(bank.questions), r[1])
history = history + [["quiz", r[0], len(bank.questions)]]
mistakes = r[1]
elif choice == "2":
if mistakes == None:
print("Take the quiz first.")
elif len(mistakes) == 0:
print("No mistakes to review.")
else:
review(mistakes)
elif choice == "3":
if mistakes == None:
print("Take the quiz first.")
elif len(mistakes) == 0:
print("No mistakes to retake.")
else:
again = [m[0] for m in mistakes]
r = quiz.attempt(again)
if r == None:
print("Retake stopped; not scored.")
else:
report(r[0], len(again), r[1])
history = history + [["retake", r[0], len(again)]]
mistakes = r[1]
elif choice == "4":
print("")
print("-- scores --")
if len(history) == 0:
print(" (no attempts yet)")
n = 0
for h in history:
n = n + 1
print(" " + str(n) + ") " + "%-7s" % h[0] + "%5s" % (str(h[1]) + "/" + str(h[2])) + "%6s" % (str(quiz.percent(h[1], h[2])) + "%"))
elif choice == "5":
running = False
else:
print("Pick a number from 1 to 5.")
print("Bye.")
bank.eml
eml# P010 quiz - the question bank. A question is a list
# [number, text, [option A, B, C, D], correct letter].
[
[1, "What gas do plants take in for photosynthesis?", ["Oxygen", "Carbon dioxide", "Nitrogen", "Helium"], "B"],
[2, "How many bones are in the adult human body?", ["106", "206", "306", "406"], "B"],
[3, "What is the chemical symbol for gold?", ["Ag", "Gd", "Au", "Go"], "C"],
[4, "Which planet is closest to the Sun?", ["Venus", "Mars", "Mercury", "Earth"], "C"],
[5, "What is the largest ocean on Earth?", ["Atlantic", "Indian", "Arctic", "Pacific"], "D"],
[6, "Which river flows through Cairo?", ["Nile", "Amazon", "Danube", "Ganges"], "A"],
[7, "On which continent is the Sahara desert?", ["Asia", "Africa", "Australia", "South America"], "B"],
[8, "What is the capital of Canada?", ["Toronto", "Vancouver", "Ottawa", "Montreal"], "C"],
] => questions
"ABCD" => letters
def option_text(q, letter):
# The text of option `letter` of question q.
for i in [0:3]:
if letters[i] == letter:
return q[2][i]
return ""
Python projection (bank.py)
questions = [[1, "What gas do plants take in for photosynthesis?", ["Oxygen", "Carbon dioxide", "Nitrogen", "Helium"], "B"], [2, "How many bones are in the adult human body?", ["106", "206", "306", "406"], "B"], [3, "What is the chemical symbol for gold?", ["Ag", "Gd", "Au", "Go"], "C"], [4, "Which planet is closest to the Sun?", ["Venus", "Mars", "Mercury", "Earth"], "C"], [5, "What is the largest ocean on Earth?", ["Atlantic", "Indian", "Arctic", "Pacific"], "D"], [6, "Which river flows through Cairo?", ["Nile", "Amazon", "Danube", "Ganges"], "A"], [7, "On which continent is the Sahara desert?", ["Asia", "Africa", "Australia", "South America"], "B"], [8, "What is the capital of Canada?", ["Toronto", "Vancouver", "Ottawa", "Montreal"], "C"]]
letters = "ABCD"
def option_text(q, letter):
for i in range(0, 4):
if letters[i] == letter:
return q[2][i]
return ""
quiz.eml
eml# P010 quiz - asking questions and marking them. An attempt asks a list of
# questions in order and returns [score, mistakes], where each mistake is
# [question, the letter given]; typing q stops the attempt, and a stopped
# attempt is not scored.
import bank
def trim(s):
0 => i
len(s) => j
while i < j and s[i] == " ":
i + 1 => i
while j > i and s[j - 1] == " ":
j - 1 => j
return s[i:j]
def answer_letter(typed):
# "A".."D" for a typed a-d or A-D, "q" to stop, "" for anything else.
if typed == "q" or typed == "Q":
return "q"
"abcd" => small
if len(typed) == 1:
for i in [0:3]:
if typed == bank.letters[i] or typed == small[i]:
return bank.letters[i]
return ""
def ask(q):
# Shows question q and returns the letter answered, or "q".
"" ^0
("Q" + str(q[0]) + ". " + q[1]) ^0
for i in [0:3]:
(" " + bank.letters[i] + ") " + q[2][i]) ^0
while True:
answer_letter(trim(input("answer> "))) => a
if a != "":
return a
"Answer with A, B, C or D (or q to stop)." ^0
def attempt(qs):
# [score, mistakes] for the questions qs, or None if the attempt stopped.
0 => score
[] => mistakes
for q in qs:
ask(q) => a
if a == "q":
return None
if a == q[3]:
score + 1 => score
"Right." ^0
else:
("Wrong - it is " + q[3] + ") " + bank.option_text(q, q[3]) + ".") ^0
mistakes + [[q, a]] => mistakes
return [score, mistakes]
def percent(score, total):
# score / total as a whole percentage, rounded half up.
return int((200 * score + total - (200 * score + total) % (2 * total)) / (2 * total))
Python projection (quiz.py)
import bank
def trim(s):
i = 0
j = len(s)
while i < j and s[i] == " ":
i = i + 1
while j > i and s[j - 1] == " ":
j = j - 1
return s[i:j]
def answer_letter(typed):
if typed == "q" or typed == "Q":
return "q"
small = "abcd"
if len(typed) == 1:
for i in range(0, 4):
if typed == bank.letters[i] or typed == small[i]:
return bank.letters[i]
return ""
def ask(q):
print("")
print("Q" + str(q[0]) + ". " + q[1])
for i in range(0, 4):
print(" " + bank.letters[i] + ") " + q[2][i])
while True:
a = answer_letter(trim(input("answer> ")))
if a != "":
return a
print("Answer with A, B, C or D (or q to stop).")
def attempt(qs):
score = 0
mistakes = []
for q in qs:
a = ask(q)
if a == "q":
return None
if a == q[3]:
score = score + 1
print("Right.")
else:
print("Wrong - it is " + q[3] + ") " + bank.option_text(q, q[3]) + ".")
mistakes = mistakes + [[q, a]]
return [score, mistakes]
def percent(score, total):
return int((200 * score + total - (200 * score + total) % (2 * total)) / (2 * total))