Build a Python Quiz Game
Build a browser-based Python quiz with validation, scoring, and difficulty.
Introduction
30 Second Summary
Programming concepts are easier to remember when each one changes something you can see. Immediate feedback turns abstract rules into a result you can test.
In this project, you will build a three-question quiz with Python in Google Colab. The finished game responds to every choice before showing a score with tailored feedback.
What You'll Build
Picture your notebook turning into a quiz that responds to every answer before revealing your final score.
By the end of this project, you'll have:
- A playable browser-based quiz where you answer three questions from your keyboard.
- An answer flow that gives immediate feedback. Its input validation refuses any choice outside A, B, or C.
- A reusable quiz structure that stores questions in a list of dictionaries. One function and one loop run every question without copied logic.
- Secret Mission: Add easy and hard question banks so the player can choose the quiz difficulty.
Are there any prerequisites?
You'll need a modern web browser with internet access plus a Google account. No prior programming experience or local Python installation is required.
Before We Start
A clear goal gives your first Python program a purpose before any code exists. This checkpoint helps you commit to building a browser-based quiz in Google Colab and connect it to your reason for learning Python.
Open Your Python Workspace
A hosted notebook lets your first effort go into writing and running Python.
Google Colab provides that workspace in your browser. You will create one notebook and prove its hosted runtime can execute a code cell.
In this step, get ready to:
- Sign in to Google Colab with your Google account.
- Create a blank notebook named Python Quiz Game.
- Run your first Python code cell and confirm its output.
Open Google Colab
A notebook contains code cells that you can run one at a time. Colab hosts the runtime that executes those cells.
- Load Google Colab by entering https://colab.research.google.com/ in your browser's address bar.
- Complete sign-in with the Google account you confirmed earlier.
You will know sign-in is complete when the landing page shows notebook creation options for your account.
Having trouble signing in?
If the sign-in flow stalls, retry it in a current version of Chrome, Firefox, or Safari.
If the page still does not load, check that your browser allows the sign-in flow for Colab.
Help me access Google Colab.
Create and name your notebook
A clear notebook name makes your quiz easy to find when you return to it. This notebook holds every code cell you build during the project.
- Choose the option on the Colab landing page that starts a blank notebook.
You will see a new notebook workspace with an empty code cell.
- Select the current notebook name at the top of the workspace.
- Enter Python Quiz Game as the new name.
You will see Python Quiz Game at the top of the notebook.
Where is the notebook stored?
Colab stores notebooks in Google Drive using the .ipynb format. Your code cells and their output stay together in one notebook.
Run your first Python cell
Running a code cell sends its instructions to the hosted runtime. The result appears directly beneath that cell.
- Add a readiness check to the first code cell by entering:
print("Python is ready!")
What does this code do?
- The print() function displays the text inside its parentheses.
- The quotation marks tell Python that Python is ready! is text to display.
Before you execute the cell, consider whether the output will match the quoted message exactly.
- Execute the first code cell with its run control.
You will see Python is ready! directly beneath the cell.
That first successful result proves your notebook can run Python code in the browser.
Don't see the readiness message?
Confirm that you executed the code cell instead of only selecting it.
Compare the cell with the full-code reference below. Check the parentheses and quotation marks closely.
Help me run my first Colab cell.
✔️ Awesome, I've got everything!
Your first cell matches the project checkpoint.
ⓧ I'd like to double check the full code
print("Python is ready!")
Your Python workspace is ready for the quiz. Next, you will turn one code cell into a question that accepts an answer.
Make One Question Come Alive
Your Python Quiz Game notebook in Google Colab can already run Python code. Now it needs to respond to a player.
A one-question version gives you a visible working game before the program grows. This keeps your first result easy to inspect.
In this step, get ready to:
- Store the question data.
- Check keyboard input with a conditional.
- Run the quiz to confirm its score.
Store and display one question
A variable gives a quiz value a reusable name. The options list keeps the answer choices in display order.
- In the first code cell from earlier, replace print("Python is ready!") with the code below:
question = "Which keyword begins a decision in Python?"
options = ["A. if", "B. print", "C. input"]
correct_answer = "A"
score = 0
print(question)
for option in options:
print(option)
What Does This Code Do?
- The question variable stores the text shown to the player.
- The options list keeps the three choices together.
- The correct_answer variable stores the letter that earns a point.
- The score variable starts at zero.
- The for loop prints each option on its own line.
- Execute the code cell.
You'll see Which keyword begins a decision in Python? above the three answer choices. The final choice reads C. input.
Don't See the Question?
Make sure the old readiness check has been replaced. Check that the indented print(option) line begins with four spaces.
Ask for help with the cell output: Help me find why my quiz question is not printing in Google Colab.
Collect and check the answer
The input() function pauses the quiz until the player types a response. The returned string becomes the value of answer.
- Add the answer-checking code below print(option) by entering:
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
print("Score: {}/1".format(score))
How Does the Answer Check Work?
- The input() call collects the player's choice.
- The .strip() method removes surrounding spaces.
- The .upper() method converts lowercase input to uppercase.
- The if block adds one point when the answer matches correct_answer.
- The else block handles an incorrect answer.
- The .format(score) call inserts the current score into the final message.
Before you run the completed quiz, what do you expect the score to show after you enter A?
- Execute the completed code cell.
- Enter A when the quiz asks for your answer.
You'll see Correct! below the answer prompt. The final line reads Score: 1/1.
You have your first interactive Python quiz working. Entering A now produces feedback plus a score.
Quiz Still Waiting or Showing Zero?
If the cell keeps running, click the answer field beside the prompt. Enter A to continue.
If the score stays at zero, check that score = score + 1 is indented inside the if block.
Ask for help with the result: Help me debug why entering A does not produce Correct! and Score: 1/1.
✔️ Awesome, I've got everything!
Great. Run the cell once more to confirm the quiz still shows Correct! plus Score: 1/1 after you enter A.
ⓧ I'd like to double check the full code
question = "Which keyword begins a decision in Python?"
options = ["A. if", "B. print", "C. input"]
correct_answer = "A"
score = 0
print(question)
for option in options:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
print("Score: {}/1".format(score))
Your one-question quiz is alive. Next, you'll grow it into a three-question game.
Grow the Quiz with Repeated Blocks
Your one-question quiz already gives the player immediate feedback. A larger quiz needs several chances to test their knowledge.
The quickest way to reach three questions is to copy the working pattern. Seeing the larger version run gives you something concrete to evaluate.
In this step, get ready to:
- Expand the quiz to three copied question blocks.
- Keep one shared score across all questions.
- Run the full quiz with the correct answer sequence.
Build a two-question version
A shared score must start once before the first question. Each question block can then add to the same total.
- Replace the current code cell with this two-question version:
score = 0
question = "Which keyword begins a decision in Python?"
options = ["A. if", "B. print", "C. input"]
correct_answer = "A"
print(question)
for option in options:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
question = "Which function displays text?"
options = ["A. input", "B. print", "C. len"]
correct_answer = "B"
print(question)
for option in options:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
What Does This Code Do?
- The score variable starts once before either question runs.
- Each block gives question a new prompt.
- Each block gives options a new list of choices.
- The correct_answer variable controls whether the shared score increases.
- The answer variable holds the latest response from the player.
- Execute the code cell.
- Enter A for the first question.
- Enter B for the second question.
You should see Correct! after each answer. The cell ends after the second feedback message.
That expansion works. Your notebook now delivers two consecutive question prompts.
Only Seeing One Question?
Confirm that the second question assignment starts after the first else block finishes.
Check that score = 0 appears only once at the top of the cell.
Help me find why my second quiz question does not run.
Complete the three-question run
The third block follows the same shape. A final print statement reports the accumulated score after all three blocks finish.
- Place your cursor after the second print("Not quite.") line.
- Press Enter twice to create one blank line.
- Insert the final question block on the new line by pasting this code:
question = "Which Python type can store several values in order?"
options = ["A. list", "B. int", "C. bool"]
correct_answer = "A"
print(question)
for option in options:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
print("Final score: {}/3".format(score))
How Does the Final Block Work?
- The third block replaces the question values before showing the new prompt.
- A correct answer adds one more point to the existing score.
- The final print() call runs after every question has been checked.
Before you run the full cell, how many times do you expect the question pattern to execute?
- Execute the complete code cell.
- Enter A at the first prompt.
- Enter B at the second prompt.
- Enter A at the third prompt.
You should see Correct! after each response. The last line should read Final score: 3/3.
You now have a complete three-question quiz. One shared score tracks every correct response.
Final Score Lower Than 3/3?
Execute the cell from the top again. Enter the sequence A, B, A when the three prompts appear.
Confirm that each correct_answer value matches its question.
Help me debug why my three-question quiz does not finish with a score of 3/3.
✔️ Awesome, I've got everything!
Your code cell now contains three questions. Double check that the notebook has stored your latest changes.
ⓧ I'd like to double check the full code
score = 0
question = "Which keyword begins a decision in Python?"
options = ["A. if", "B. print", "C. input"]
correct_answer = "A"
print(question)
for option in options:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
question = "Which function displays text?"
options = ["A. input", "B. print", "C. len"]
correct_answer = "B"
print(question)
for option in options:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
question = "Which Python type can store several values in order?"
options = ["A. list", "B. int", "C. bool"]
correct_answer = "A"
print(question)
for option in options:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Not quite.")
print("Final score: {}/3".format(score))
How the Full Cell Fits Together
The cell initializes score once. Every copied block can therefore add to the same total.
The final score appears only after the third conditional finishes. Its position keeps the result at the end of the game.
Inspect the repeated pattern
The quiz works from beginning to end. Its three copied sections now show how much code another question would require.
- Count every occurrence of print(question) in the code cell.
- Locate every input() line.
- Locate every if answer == correct_answer: conditional.
- Identify the display loop that would appear a fourth time after adding another question.
- Identify the input line that would appear a fourth time after adding another question.
- Identify the checking conditional that would appear a fourth time after adding another question.
Why Repetition Becomes Costly
A fourth question requires another copy of the display loop. It also requires another input line.
The entire checking conditional appears again. Any future change to the question flow must be applied to every copy.
That is the designed shortfall uncovered. Your quiz plays correctly while its repeated structure makes every new question harder to maintain.
Next, you'll turn this repeated pattern into a structure that is easier to extend.
Refactor with Data, a Function, and a Loop
Your three-question quiz now works in Google Colab. Each question repeats the same instructions.
That copied structure makes every change easy to miss in one place. This refactor gives the repeated work one reusable path.
In this step, get ready to:
- Store three questions in a list of dictionaries.
- Create one function that asks a question.
- Run every question through one scoring loop.
Store the questions as structured data
A list keeps the three questions in order. Each dictionary keeps one question's details together.
- Select the copied quiz code in the open Python Quiz Game code cell.
- Replace the selected code with the question data below:
questions = [
{
"prompt": "Which keyword begins a decision in Python?",
"options": ["A. if", "B. print", "C. input"],
"answer": "A",
},
{
"prompt": "Which function displays text?",
"options": ["A. input", "B. print", "C. len"],
"answer": "B",
},
{
"prompt": "Which Python type can store several values in order?",
"options": ["A. list", "B. int", "C. bool"],
"answer": "A",
},
]
What does this data represent?
- The questions list holds three dictionaries in one ordered collection.
- The prompt key stores the text shown to the player.
- The options key stores the three displayed choices.
- The answer key stores the correct letter.
- Add this temporary expression beneath the closing bracket:
questions
Why display the list?
The temporary questions expression makes Colab display the collection. You can inspect all three entries before building the quiz logic.
- Execute the code cell.
You'll see a list containing three dictionary entries. Each entry shows one prompt with its options plus its answer.
Don't see the three dictionaries?
- Check that the temporary questions expression is the final line in the cell.
- Confirm that every opening bracket has a matching closing bracket.
Help me check my question data for missing brackets or commas.
Build one reusable question function
A function gives the repeated question routine one name. Its return value tells the scoring code whether the player's answer was correct.
- Select the temporary questions expression at the bottom of the cell.
- Replace it with two blank lines followed by this function:
def ask_question(question):
print()
print(question["prompt"])
for option in question["options"]:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == question["answer"]:
print("Correct!")
return True
print("Not quite. The correct answer is {}.".format(question["answer"]))
return False
How does the function remove repetition?
- The question parameter gives the function one dictionary to process.
- The inner for loop prints every choice stored under options.
- A correct answer returns True to the scoring code.
- An incorrect answer returns False after showing the expected letter.
Drive the quiz with one loop
The outer loop sends each dictionary into ask_question(question). A True return adds one point to score.
- Place your cursor beneath return False.
- Add two blank lines followed by this quiz runner:
score = 0
print("Welcome to the Python Quiz!")
for question in questions:
if ask_question(question):
score = score + 1
print("Final score: {}/{}".format(score, len(questions)))
How does the scoring loop work?
- The score starts at zero before the quiz begins.
- The outer for loop passes each dictionary to the reusable function.
- The if block adds a point only when the function returns True.
- The final line uses len(questions) to display the total number of questions.
✔️ Awesome, I've got everything!
Your question data now feeds one reusable function plus one scoring loop. Keep the cell ready for the test below.
ⓧ I'd like to double check the full code
questions = [
{
"prompt": "Which keyword begins a decision in Python?",
"options": ["A. if", "B. print", "C. input"],
"answer": "A",
},
{
"prompt": "Which function displays text?",
"options": ["A. input", "B. print", "C. len"],
"answer": "B",
},
{
"prompt": "Which Python type can store several values in order?",
"options": ["A. list", "B. int", "C. bool"],
"answer": "A",
},
]
def ask_question(question):
print()
print(question["prompt"])
for option in question["options"]:
print(option)
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer == question["answer"]:
print("Correct!")
return True
print("Not quite. The correct answer is {}.".format(question["answer"]))
return False
score = 0
print("Welcome to the Python Quiz!")
for question in questions:
if ask_question(question):
score = score + 1
print("Final score: {}/{}".format(score, len(questions)))
How to use this reference
This reference shows the complete code cell for this step. Its blank lines separate the data from the function plus the quiz runner.
Before you execute the cell, predict what the quiz will do after you enter D.
- Execute the completed code cell.
- Enter D at the first answer prompt.
You'll see Not quite. The correct answer is A.. The second question then appears.
- Enter B for the second question.
- Enter A for the third question.
You'll see immediate feedback after each choice. The last line shows Final score: 2/3.
That refactor pays off. All three questions now run through one reusable path.
The program accepts D as a genuine answer before marking it wrong. This visible gap shows why the quiz needs input validation.
Quiz stops before the final score?
- Confirm that ask_question(question) appears above the scoring loop.
- Check that the lines inside each for or if block use consistent indentation.
- Look for the active answer field if the cell still shows that it is running.
Help me debug my refactored quiz.
Your refactored quiz is easier to extend. Next, you'll make it refuse choices outside A, B, or C.
Make the Quiz Reject Invalid Answers
Your Python quiz now asks three questions through one reusable function. However, an invalid choice such as D still consumes a question as though it were a real answer.
This step adds input validation through a retry loop. The completed quiz keeps asking until the player enters A, B, or C.
In this step, get ready to:
- Reject invalid choices with get_valid_answer().
- Calculate the player's final percentage.
- Display feedback that matches the player's score.
Build the validation loop
A validation loop checks the player's response before the quiz scores it. while True keeps the loop active until the function returns an allowed choice.
- Place your cursor on the blank line immediately above ask_question(question) in the existing code cell.
- Add the validation function by pasting this code:
def get_valid_answer():
while True:
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer in ["A", "B", "C"]:
return answer
print("Please enter A, B, or C.")
What Does This Function Do?
- The while True loop keeps requesting an answer until return ends the function.
- The .strip() method removes surrounding spaces. The .upper() method converts lowercase letters to uppercase.
- The membership check accepts only values found in ["A", "B", "C"].
- The final print() explains the valid choices before the loop asks again.
- Find this answer line inside ask_question(question):
answer = input("Your answer (A, B, or C): ").strip().upper()
How Does the Current Line Behave?
This line collects one response. Any value then reaches the correctness comparison.
- Replace the current answer line with this function call:
answer = get_valid_answer()
Why Use the Function Here?
The function call pauses ask_question(question) until it receives a valid choice. Only that validated answer reaches the scoring logic.
Before you run the updated quiz, make a mental prediction about whether D consumes the first question or triggers another prompt.
- Run the updated code cell.
- Enter D at the first answer prompt.
You'll see Please enter A, B, or C. followed by the same answer prompt. The first question remains active.
- Enter A for the first question.
- Enter B for the second question.
- Enter A for the third question.
You'll see Final score: 3/3 after all three valid answers. Your quiz now refuses unsupported choices without losing a question.
Does D Still Count as Incorrect?
Check that answer = get_valid_answer() appears inside ask_question(question) with the same indentation as the previous answer line.
Confirm that get_valid_answer() appears above ask_question(question) in the same code cell.
Help me fix my quiz validation loop.
Show the final percentage
A raw score shows how many questions the player answered correctly. A percentage makes that result easier to compare when the quiz grows.
- Find the existing final score line near the bottom of the code cell.
- Replace that line with these percentage calculations and output lines:
percentage = score / len(questions) * 100
print()
print("Final score: {}/{} ({:.0f}%)".format(score, len(questions), percentage))
How Is the Percentage Calculated?
- The expression divides score by the number returned from len(questions).
- Multiplying by 100 converts the result into a percentage.
- The {:.0f} field displays that percentage with no decimal places.
- The empty print() creates a visual gap before the final result.
- Run the updated code cell.
- Enter A for the first question.
- Enter B for the second question.
- Enter A for the third question.
You'll see Final score: 3/3 (100%) beneath the final question.
Percentage Missing From the Score?
Check that the percentage line appears before the final score output. Confirm that questions is spelled the same way as the list at the top of the cell.
Help me fix the percentage output.
Add tailored feedback
The final score tells the player what happened. Score-based conditionals turn that number into feedback for a perfect score, a near-perfect score, or another attempt.
- Place your cursor immediately below the final score output.
- Add the closing feedback by pasting this conditional block:
if score == len(questions):
print("Perfect score! You are off to a great start.")
elif score == 2:
print("Nice work! Review one topic and try again.")
else:
print("Good first attempt. Run the quiz again and improve your score.")
How Does the Feedback Change?
- The if branch compares score with the total number of questions.
- The elif branch handles a score of 2.
- The else branch handles every lower score.
Before the final run, predict how the quiz responds to D before it calculates a perfect score.
- Run the completed code cell.
- Enter D at the first answer prompt.
- Enter A when the same prompt appears again.
- Enter B for the second question.
- Enter A for the third question.
You'll first see Please enter A, B, or C. with the first question still waiting. After the valid answers, you'll see Final score: 3/3 (100%) followed by Perfect score! You are off to a great start..
You have closed the input gap. The quiz now validates every choice before scoring it.
Feedback Not Matching the Score?
Make sure the if, elif, and else lines align with one another. Each feedback print() line needs one level of indentation.
Confirm that the feedback block appears after the final score output. Code above the quiz loop can run before score contains the final result.
Help me fix the final feedback.
✔️ Awesome, I've got everything!
Your completed notebook validates each answer. It also displays a percentage with score-based feedback.
ⓧ I'd like to double check the full code
questions = [
{
"prompt": "Which keyword begins a decision in Python?",
"options": ["A. if", "B. print", "C. input"],
"answer": "A",
},
{
"prompt": "Which function displays text?",
"options": ["A. input", "B. print", "C. len"],
"answer": "B",
},
{
"prompt": "Which Python type can store several values in order?",
"options": ["A. list", "B. int", "C. bool"],
"answer": "A",
},
]
def get_valid_answer():
while True:
answer = input("Your answer (A, B, or C): ").strip().upper()
if answer in ["A", "B", "C"]:
return answer
print("Please enter A, B, or C.")
def ask_question(question):
print()
print(question["prompt"])
for option in question["options"]:
print(option)
answer = get_valid_answer()
if answer == question["answer"]:
print("Correct!")
return True
print("Not quite. The correct answer is {}.".format(question["answer"]))
return False
score = 0
print("Welcome to the Python Quiz!")
for question in questions:
if ask_question(question):
score = score + 1
percentage = score / len(questions) * 100
print()
print("Final score: {}/{} ({:.0f}%)".format(score, len(questions), percentage))
if score == len(questions):
print("Perfect score! You are off to a great start.")
elif score == 2:
print("Nice work! Review one topic and try again.")
else:
print("Good first attempt. Run the quiz again and improve your score.")
Secret mission
Add Difficulty Levels
Give each player control over the quiz they face. You will add easy and hard question banks, validate the player's difficulty choice, and select the matching questions dynamically.
Clean Up Your Resources
Clean Up Your Resources
Google Colab is free of charge for this project. Choose to keep the notebook available, pause your session, or delete it entirely.
Resources you used:
- The Python Quiz Game.ipynb Google Colab notebook stored in Google Drive.
Keep everything running
No action needed. Choose this if you want to keep the notebook available for more quiz experiments.
- Leave Python Quiz Game.ipynb in Google Drive.
- Rerun the extended code cell in Google Colab whenever you want to play either difficulty level.
Pause - I'll come back to this later
Close your current session so the hosted runtime can time out. Your notebook remains stored in Google Drive.
- Close the Google Colab browser tab.
- Return to Python Quiz Game.ipynb in Google Drive when you are ready to continue.
Delete - I don't want to use this again
Deleting the notebook removes your saved quiz code from Google Drive. The hosted runtime contains no separate project resource that you need to delete.
- Close the Google Colab browser tab.
- Locate Python Quiz Game.ipynb in Google Drive.
- Delete Python Quiz Game.ipynb from Google Drive.
- Confirm that Python Quiz Game.ipynb no longer appears in your Google Drive files.
Nice Work!
Nice Work!
You did it. Your Google Colab notebook now runs a complete Python quiz with selectable difficulty levels.
You've learned how to:
- Built a playable quiz that collects keyboard input. It gives immediate feedback. It finishes with a final score plus a tailored message.
- Organized questions with lists and dictionaries. You replaced repeated logic with ask_question(question). A loop now runs every question.
- Added input validation with get_valid_answer(). Invalid choices trigger another prompt instead of silently affecting the score.
- Secret Mission: Added easy and hard question banks. The get_difficulty() function validates the player's choice. The quiz then selects the matching questions dynamically.
Ready to quiz yourself?