Mini Project: Command-Line Quiz Game
Objectives
By the end of this chapter, you should be able to:
- Combine functions, parameters, data structures, and recursion into one working program
- Break a larger problem down into smaller functions, each with a single job
💡 Why this matters: Everything up to this point has been one concept at a time, in isolation. Real programs, even small ones, mix all of it together. This is the first project in the course big enough that you’ll need to plan its structure before writing any code.
The Project
Build a command-line quiz game: it asks the player a series of questions, keeps score, and reports the result at the end. Nothing here requires anything beyond what you’ve learned so far: variables, strings, booleans, lists, dictionaries, and functions (including recursion) are the entire toolkit.
Core Requirements
- Store your questions as a list of dictionaries. You already know lists (Module 2) and dictionaries (Module 3) on their own; here you combine them, so each element of the list is itself a dictionary with a question, the correct answer, and a list of options, something like:
QUESTIONS = [
{
"question": "What does len() return for the string 'hello'?",
"options": ["4", "5", "6"],
"answer": "5",
},
{
"question": "Which keyword defines a function?",
"options": ["func", "def", "function"],
"answer": "def",
},
]
- Write
ask_question(question_dict): prints the question and its options, usesinput()to get the player’s answer, and returnsTrueorFalsedepending on whether they got it right. - Write
run_quiz(questions): loops over every question, keeps a running score usingask_question, and returns the final score. - Write
report_result(score, total): takes the score and prints a message appropriate to how well the player did (for example, a different message for a perfect score versus a middling one versus a poor one).
A Recursive Extra: Play Again
Write play_quiz() as a recursive function: it runs the quiz once via run_quiz, reports the result, then asks “Play again? (y/n)” with input(). If the player answers "y", play_quiz() calls itself again instead of looping. If they answer anything else, it stops (the base case).
def play_quiz():
score = run_quiz(QUESTIONS)
report_result(score, len(QUESTIONS))
again = input("Play again? (y/n) ")
if again.lower() == "y":
play_quiz() # recursive case
# anything else is the base case: the function just ends
Suggested Structure
You don’t have to follow this exactly, but it’s a reasonable shape to aim for:
QUESTIONS = [
# your question dictionaries here
]
def ask_question(question_dict):
print(question_dict["question"])
for option in question_dict["options"]:
print(f" - {option}")
answer = input("Your answer: ")
return answer.strip() == question_dict["answer"]
def run_quiz(questions):
score = 0
for question in questions:
if ask_question(question):
score += 1
return score
def report_result(score, total):
if score == total:
print(f"Perfect! {score}/{total}")
elif score >= total / 2:
print(f"Not bad. {score}/{total}")
else:
print(f"{score}/{total}. Worth another try!")
def play_quiz():
score = run_quiz(QUESTIONS)
report_result(score, len(QUESTIONS))
if input("Play again? (y/n) ").lower() == "y":
play_quiz()
play_quiz()
Bonus Extensions
-
Track and print which specific questions the player got wrong, at the end.
-
Shuffle the question order each time, so a replay isn’t identical. The
randommodule has ashuffle()function that reorders a list in place:import random QUESTIONS = [ {"question": "...", "options": [...], "answer": "..."}, {"question": "...", "options": [...], "answer": "..."}, ] random.shuffle(QUESTIONS) # QUESTIONS is now in a random order -
Add a
**kwargs-basedask_questionvariant that accepts an optionalhintand prints it if the player answers wrong on a first attempt, giving them one retry. -
Add at least one question whose options are computed rather than hardcoded (for example, a question about
len()of a string your program generates first).
Try It
- Build the project following the suggested structure (or your own design), with at least five questions.
- Play through it once, missing at least one question on purpose, and confirm your score and report are correct.
- Confirm the recursive “play again” flow works: say yes once, then no, and confirm it actually stops.
- Attempt at least one bonus extension.
Recap
You’ve now built a complete, working program, not just answered isolated exercises, using nothing but the tools from this module: functions, parameters, data structures, and recursion. That’s the real test of whether a concept has actually sunk in: can you reach for it unprompted, as part of something bigger.
Next module: debugging your code, and working with Python’s module system.