1. DRY (Don't Repeat Yourself)
You should define containers for your questions and answers. This way you can avoid having to repeat the whole logic for every question.
As a first step, I would advise to put all your question texts, answer texts, choice texts and correct answer texts in lists.
Then you can write a function that iterates over these lists (at the same time) and does the actual game. For this you can use zip
.
questions = ["What is 1 + 1",
"Who is the 45th president of the United States?",
"True or False... The Toronto Maple Leafs have won 13 Stanley Cups?",
"What was the last year the Toronto Maple Leafs won the Stanley Cup?",
"True or False... The current Prime Minister of Canada is Pierre Elliot Tredeau?"]
answer_choices = ["a)1\nb)2\nc)3\nd)4\n:",
"a)Barack Obama\nb)Hillary Clinton\nc)Donald Trump\nd)Tom Brady\n:",
":",
"a)1967\nb)1955\nc)1987\nd)1994\n:",
":"]
correct_choices = [{"b", "2"},
{"c", "donald trump"},
{"true", "t"},
{"a", "1967"},
{"false", "f"}]
answers = ["1 + 1 is 2",
"The 45th president is Donald Trump",
"",
"The last time the Toronto Maple Leafs won the Stanley Cup was 1967",
"The current Prime Minster of Canada is Justin Tredeau"]
def quiz():
score = 0
for question, choices, correct_choice, answer in zip(questions, answer_choices, correct_choices, answers):
print(question)
user_answer = input(choices).lower()
if user_answer in correct_choice:
print("Correct")
score += 1
else:
print("Incorrect", answer)
print(score, "out of", len(questions), "that is", float(score / len(questions)) * 100, "%")
if __name__ == "__main__":
quiz()
2. OOP (Object-Oriented Programming)
A second step could be trying to encapsulate this whole object of a question into an actual Python object. That is, a question is an object that has a question(text), an answer, answer choices and correct answer choices.
You could define a class
like this:
class Question:
def __init__(self, question, answer, choices, correct):
self.question = question
self.answer = answer
self.choices = choices
self.correct = correct
But this class would be nothing but a data storage for these strings. Whenever you have this, you can use a collections.namedtuple
.
>>> from collections import namedtuple
>>> Question = namedtuple("Question", "question answer choices correct")
>>> q = Question("What is 1 + 1", "1 + 1 is 2", "a)1\nb)2\nc)3\nd)4\n:", {"b", "2"})
>>> q.question
'What is 1 + 1'
>>> q[3]
{'b', '2'}
So a Question
is just a tuple with nice names, so that afterwards q.question = q[0] = 'What is 1 + 1'
, and so on.
from collections import namedtuple
Question = namedtuple("Question", "question answer choices correct")
questions = [Question("What is 1 + 1", "1 + 1 is 2", "a)1\nb)2\nc)3\nd)4\n:", {"b", "2"}),
...]
def quiz():
score = 0
for question in questions:
print(question.question)
user_answer = input(question.choices).lower()
if user_answer in question.correct:
print("Correct")
score += 1
else:
print("Incorrect", question.answer)
print(score, "out of", len(questions), "that is",
float(score / len(questions)) * 100, "%")
if __name__ == "__main__":
quiz()
3. The last push
Last, but not least, you could make enumerating the choices automatic, using string.ascii_lowercase
(which is simply the lowercase alphabet) and str.join
ing it with newlines and the ")"
used to separate a letter from the choice associated with that letter.
You could also pass a list of Question
s directly to the function, allowing making different quizzes (by choosing randomly 5 questions out of a pool of 100 question, for example).
Finally, you could use str.format
to make the print of the final score a bit nicer.
import string
from collections import namedtuple
Question = namedtuple("Question", "question answer choices correct")
questions = [Question("What is 1 + 1", "1 + 1 is 2",
["1", "2", "3", "4"], {"b", "2"}), ...]
def quiz(questions):
score = 0
for question in questions:
print(question.question)
for line in zip(string.ascii_lowercase, question.choices):
print(") ".join(line))
user_answer = input().lower()
if user_answer in question.correct:
print("Correct")
score += 1
else:
print("Incorrect", question.answer)
print("{} out of {} that is {} %".format(score, len(questions), score / len(questions) * 100))
if __name__ == "__main__":
# Use all questions but the first
quiz(questions[1:])
WROOOOONG!
" \$\endgroup\$