forked from realpython/materials
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquiz.py
More file actions
106 lines (81 loc) · 3.08 KB
/
Copy pathquiz.py
File metadata and controls
106 lines (81 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# quiz.py
import pathlib
import random
from string import ascii_lowercase
try:
import tomllib
except ModuleNotFoundError:
import tomli as tomllib
NUM_QUESTIONS_PER_QUIZ = 5
QUESTIONS_PATH = pathlib.Path(__file__).parent / "questions.toml"
def run_quiz():
questions = prepare_questions(
QUESTIONS_PATH, num_questions=NUM_QUESTIONS_PER_QUIZ
)
num_correct = 0
for num, question in enumerate(questions, start=1):
print(f"\nQuestion {num}:")
num_correct += ask_question(question)
print(f"\nYou got {num_correct} correct out of {num} questions")
def prepare_questions(path, num_questions):
topic_info = tomllib.loads(path.read_text())
topics = {
topic["label"]: topic["questions"] for topic in topic_info.values()
}
topic_label = get_answers(
question="Which topic do you want to be quizzed about",
alternatives=sorted(topics),
)[0]
questions = topics[topic_label]
num_questions = min(num_questions, len(questions))
return random.sample(questions, k=num_questions)
def ask_question(question):
correct_answers = question["answers"]
alternatives = question["answers"] + question["alternatives"]
ordered_alternatives = random.sample(alternatives, k=len(alternatives))
answers = get_answers(
question=question["question"],
alternatives=ordered_alternatives,
num_choices=len(correct_answers),
hint=question.get("hint"),
)
if correct := (set(answers) == set(correct_answers)):
print("⭐ Correct! ⭐")
else:
is_or_are = " is" if len(correct_answers) == 1 else "s are"
print("\n- ".join([f"No, the answer{is_or_are}:"] + correct_answers))
if "explanation" in question:
print(f"\nEXPLANATION:\n{question['explanation']}")
return 1 if correct else 0
def get_answers(question, alternatives, num_choices=1, hint=None):
print(f"{question}?")
labeled_alternatives = dict(zip(ascii_lowercase, alternatives))
if hint:
labeled_alternatives["?"] = "Hint"
for label, alternative in labeled_alternatives.items():
print(f" {label}) {alternative}")
while True:
plural_s = "" if num_choices == 1 else f"s (choose {num_choices})"
answer = input(f"\nChoice{plural_s}? ")
answers = set(answer.replace(",", " ").split())
# Handle hints
if hint and "?" in answers:
print(f"\nHINT: {hint}")
continue
# Handle invalid answers
if len(answers) != num_choices:
plural_s = "" if num_choices == 1 else "s, separated by comma"
print(f"Please answer {num_choices} alternative{plural_s}")
continue
if any(
(invalid := answer) not in labeled_alternatives
for answer in answers
):
print(
f"{invalid!r} is not a valid choice. " # noqa
f"Please use {', '.join(labeled_alternatives)}"
)
continue
return [labeled_alternatives[answer] for answer in answers]
if __name__ == "__main__":
run_quiz()