generated from Code-Institute-Org/python-essentials-template
-
Notifications
You must be signed in to change notification settings - Fork 3
/
create_quiz.py
342 lines (272 loc) · 9.25 KB
/
create_quiz.py
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
from helpers import ask_any_key, ask_yes_no, clear, is_quit
import requests
import json
import urllib.parse
from termcolor import cprint
from time import sleep
def get_category_data():
"""
Makes a call the the Quiz API and returns the list of available categories
"""
result = json.loads(requests.get(
"https://opentdb.com/api_category.php").text)["trivia_categories"]
return result
def create_categories_dict(categories_data):
"""
Creates a dictionary of quiz
categories in the format id: category
"""
# Choose how many categories to display.
NUM_OF_CATS_TO_DISPLAY = 17
cats_dict = {}
for x in range(NUM_OF_CATS_TO_DISPLAY):
key, value = categories_data[x].values()
cats_dict[key] = value
return cats_dict
def get_session_token():
"""
Makes a call to the Quiz API for a Session token which keeps track of the
questions so the user doesn't receive the same question twice.
"""
result = json.loads(requests.get(
"https://opentdb.com/api_token.php?command=request").text)["token"]
return result
# Quiz API Setup
try:
CATEGORIES_DATA = get_category_data()
QUIZ_CATEGORIES = create_categories_dict(CATEGORIES_DATA)
SESSION_TOKEN = get_session_token()
except Exception:
cprint("🚫 The Quiz API could not be reached!\n", "red")
print("See https://opentdb.com/ \n")
print("Please try again later.")
quit()
def get_quiz_questions(num_qs, cat, diff):
"""
Makes a call to the Quiz API and returns a list of
multiple choice questions with category, type, difficulty,
question, correct_answer and incorrect_answers
"""
result = json.loads(requests.get(
f"https://opentdb.com/api.php?amount={num_qs}&category={cat}&difficulty={diff}&type=multiple&token={SESSION_TOKEN}&encode=url3986").text)["results"] # noqa
return result
class Game:
"""
Generates a Quiz Game,
Expects 5 parameters: Quiz Title, Number of Rounds,
Number of Questions in a round, a list of the categories
for each round, and the difficulty
Args:
quiz_title: string Title for the Quiz
num_rounds: int Number of rounds
num_qs: int Number of questions per round
categories: A list of ints coresponding to the
Quiz API's IDs of the categories chosen
difficulty: string "easy", "medium", or "hard"
"""
def __init__(self, quiz_title, num_rounds, num_qs, categories, difficulty):
self.quiz_title = quiz_title
self.num_rounds = num_rounds
self.num_questions = num_qs
self.categories = categories
self.difficulty = difficulty
self.rounds = [Round(x+1, self.num_questions, self.categories[x],
self.difficulty) for x in range(self.num_rounds)]
def get_quiz_title(self):
return self.quiz_title
def get_num_rounds(self):
return self.num_rounds
def get_num_questions(self):
return self.num_questions
def get_categories(self):
return self.categories
def get_rounds(self):
return self.rounds
def describe(self):
cats_text = [QUIZ_CATEGORIES[cat] for cat in self.categories]
print(f"Quiz title: {self.quiz_title}\n{self.num_rounds}"
f" rounds of {self.num_questions} {self.difficulty} questions.\n"
f"\nCategories are:\n")
print(*cats_text, sep=", ")
class Round:
"""
Generates a Quiz Round
Args:
round_num: int Order of the round in the game
num_qs: int Number of questions in round
category: int the ID of the category
difficulty: string "easy", "medium" or "hard"
"""
def __init__(self, round_num, num_qs, category, difficulty):
self.round_num = round_num
self.num_qs = num_qs
self.category = category
self.difficulty = difficulty
question_data = get_quiz_questions(num_qs, category, difficulty)
self.questions_list = [Question(**question)
for question in question_data]
def get_round_num(self):
return self.round_num
def get_num_qs(self):
return self.num_qs
def get_category(self):
return self.category
def get_difficulty(self):
return self.difficulty
def get_questions(self):
return self.questions_list
class Question:
"""
Creates a Quiz Question instance
Args:
category: int, the ID of the category
q_type: "multiple" or "boolean"
difficulty: "easy", "medium" or "hard"
question: string containing the question
correct_answer: string containing the correct answer
incorrect_answers: list of strings of incorrect answers
"""
def __init__(
self, category, type, difficulty, question,
correct_answer, incorrect_answers):
self.category = category
self.qtype = type
self.difficulty = difficulty
self.question = urllib.parse.unquote(question)
self.correct_answer = urllib.parse.unquote(correct_answer)
self.incorrect_answers = [urllib.parse.unquote(
ans) for ans in incorrect_answers]
def get_category(self):
return self.category
def get_qtype(self):
return self.qtype
def get_difficulty(self):
return self.difficulty
def get_question(self):
return self.question
def get_correct_answer(self):
return self.correct_answer
def get_incorrect_answers(self):
return self.incorrect_answers
def setup_new_quiz():
"""
Asks user for inputs and creates a new quiz based on the inputs
"""
clear()
# Ask for the name of the Quiz
while True:
try:
title = str(input("What is the name of your Quiz Game? \n"))
if is_quit(title):
return None
except TypeError:
continue
if title == "":
print("Please enter a name for the quiz. \n")
continue
else:
break
sleep(1)
clear()
# Ask how many round should the Quiz game have
while True:
try:
rounds = input("How many rounds should the quiz have? \n")
if is_quit(rounds):
return None
else:
rounds = int(rounds)
except ValueError:
cprint("You must enter a number of rounds for the quiz.\n",
"red")
continue
if rounds < 0:
cprint("Sorry, you must enter a positive number.\n", "red")
continue
if rounds > 10:
cprint("Sorry, you can only have a maximum of 10 rounds.",
"red")
continue
else:
break
sleep(1)
clear()
# Ask how many questions should be in each round
while True:
try:
q_num = input("How many questions in each round? \n")
if is_quit(q_num):
return None
else:
q_num = int(q_num)
except ValueError:
clear()
print("You must enter a number of questions for each round.\n")
continue
if q_num < 0:
clear()
cprint("Sorry, you must enter a positive number\n", "red")
continue
if q_num > 10:
cprint("Sorry, you can only have a max of 10"
"questions per round.", "red")
continue
else:
break
sleep(1)
clear()
# Print the list of Categories, ask what category
# each round should be
print_cats = ""
for key in QUIZ_CATEGORIES:
print_cats += f"{key}: {QUIZ_CATEGORIES[key]} \n"
cats_selected = []
for x in range(1, rounds+1):
while True:
try:
print("Available Categories:")
print(print_cats)
cat = input(f"Choose a category for Round {x}: \n")
if is_quit(cat):
return None
else:
cat = int(cat)
except ValueError:
clear()
cprint(f"Please enter a valid category number from "
f"the list for round {x}. \n", "red")
continue
if cat not in list(QUIZ_CATEGORIES):
clear()
cprint(f"Please enter a valid category number from "
f"the list for round {x}. \n", "red")
continue
else:
cats_selected.append(cat)
clear()
break
sleep(1)
clear()
# Ask what difficulty the questions should be
while True:
try:
diff = input("What difficulty should the questions be? \n \n"
"Easy, Medium or Hard? \n").lower()
except ValueError:
continue
if is_quit(diff):
return None
if diff not in ["easy", "medium", "hard"]:
continue
else:
break
sleep(1)
clear()
game_obj = Game(title, rounds, q_num, cats_selected, diff)
game_obj.describe()
if ask_yes_no("Are these settings correct?"):
return game_obj
else:
print("Okay, let's try again...")
sleep(1)
clear()