LEARN PYTHON | Project: A Quiz With A Scoreboard

Lesson objective

Build a quiz from a list of question records, validate choices, calculate player scores and display an ordered session scoreboard without separating names from results.

Learn

03.6 | PROJECT: A QUIZ WITH A SCOREBOARD

01 | DEFINE A QUIZ YOU CAN TEST

The project asks each player three multiple-choice questions. A player selects an option number. Each correct answer earns one point; a wrong accepted answer earns zero.

Invalid option text is retried for the same question and does not move to the next question. After all questions, the program stores a name and score on a session scoreboard. Another player can take the same quiz, or enter quit at the name prompt to finish.

The scoreboard is kept only during the current run. Displaying it does not save it to a file or database. Persistence is a later course topic.

02 | STORE QUESTION DATA SEPARATELY

Each question is a dictionary with prompt, options and answer. options is a list of strings; answer is the accepted option code as a string such as "2".

A list holds the question dictionaries in quiz order. Adding a question means adding another consistent record rather than copying an entire decision block.

The author must keep answer consistent with the numbered options. The core program assumes a non-empty, correctly authored question bank. A successful player-input check does not verify the quality of the stored answers.

question = {"prompt": "Which type stores text?",
            "options": ["int", "str", "bool"],
            "answer": "2"}
print(question["prompt"])
print(question["options"][1])

EXPECTED OUTPUT

Which type stores text?
str

03 | DISPLAY OPTIONS WITH NUMBERS

enumerate(options, start=1) supplies a one-based display number and each option string. The underlying options list still begins at index zero.

The player enters a display code. This design compares that code with the answer code directly, so no subtraction or list indexing is needed to check correctness.

Build the permitted codes from the option count. A three-option question accepts "1", "2" and "3". It does not accept "0" or "4", and it does not need integer conversion just to compare these labels.

04 | RETRY INVALID CHOICES IN THE CURRENT QUESTION

Read a stripped response. While it is not in valid_choices, print feedback and read again. The question loop advances only after an accepted response has been processed.

An input such as "two" is rejected as an unsupported option code, not sent to int conversion. This is a deliberate text-code design. "02" is also rejected even if a human might interpret it as two.

Check each question’s own option count rather than assuming every question always has exactly three choices.

05 | COUNT POINTS FOR ONE PLAYER

Initialise score once when a new player starts. For each accepted answer, compare the response with question["answer"]. If they match, add one; otherwise give correction feedback without increasing the score.

The outer player loop and inner question loop have different roles. The player’s score reset belongs inside the player loop, before the question loop. Resetting it per question would lose earlier points.

Percentage is score / len(questions) × 100. The known non-empty question bank prevents a zero divisor; an editable empty bank would require a guard.

06 | KEEP A RESULT AS ONE RECORD

The scoreboard stores a tuple (score, name) for each completed player. That keeps a result paired with its owner. Duplicate player names are allowed and remain separate completed plays in this version.

sorted(scoreboard, reverse=True) returns a new descending list. Tuple comparison considers score first, then name if scores tie. Here tied names display in descending text order; that is an explicit display rule, not a claim that one tied player deserves a higher score.

The printed positions are display positions, not shared competition ranks. A more sophisticated ranking policy is a useful later extension.

07 | THE COMPLETE CORE QUIZ

Read the data records first, then trace the two loop levels. The program uses collection methods and control flow already introduced, without requiring a function definition from the next section.

# Session quiz: authored question bank must be non-empty and consistent.
questions = [
    {"prompt": "Which Python type stores text?",
     "options": ["int", "str", "bool"], "answer": "2"},
    {"prompt": "What is the first non-negative list index?",
     "options": ["0", "1", "-1"], "answer": "1"},
    {"prompt": "Which collection keeps distinct members?",
     "options": ["list", "tuple", "set"], "answer": "3"}
]
scoreboard = []

print("Python collections quiz")
while True:
    name = input("Player first name, or quit to finish: ").strip()
    if name == "quit":
        break
    if not name:
        print("Enter a non-empty name")
        continue

    score = 0
    for question in questions:
        print()
        print(question["prompt"])
        for number, option in enumerate(question["options"], start=1):
            print(f"{number}. {option}")
        valid_choices = [str(number) for number in range(1, len(question["options"]) + 1)]
        response = input("Option number: ").strip()
        while response not in valid_choices:
            print("Choose one of the displayed option numbers")
            response = input("Option number: ").strip()
        if response == question["answer"]:
            score += 1
            print("Correct")
        else:
            print(f"Not correct. Answer code: {question['answer']}")

    percentage = score / len(questions) * 100
    print(f"{name}: {score}/{len(questions)} ({percentage:.1f}%)")
    scoreboard.append((score, name))

print()
print("Session scoreboard: score descending, then name descending for ties")
if scoreboard:
    ranked = sorted(scoreboard, reverse=True)
    for position, result in enumerate(ranked, start=1):
        score, name = result
        print(f"Display position {position}: {name} - {score}/{len(questions)}")
else:
    print("No completed players")

08 | TRACE A TWO-PLAYER SESSION

Maya enters codes 2, 1 and 3, earning three points. Kai enters 1, 1 and 2, earning one point. The scoreboard arrival order is [(3, "Maya"), (1, "Kai")].

If Kai plays first, arrival order changes but sorted display still places the three-point result first. The tuple keeps name and score together while ordering changes.

An invalid option such as 9 causes a retry in the same question. The score does not change and the question loop has not advanced to another record.

09 | TRY A BROWSER QUIZ MODEL

The model uses the same three questions and permits one completed player at a time. Its scoreboard lasts while this page is open. It does not execute Python or store results on the server.

    10 | TEST THE RULES, NOT ONLY A HAPPY PATH

    All correct codes 2, 1, 3 should give three points and 100.0%. All wrong accepted codes should give zero. Invalid code 9 followed by 2 for the first question should retry and then score one for that question.

    Immediate quit should produce No completed players. An empty player name should retry the name prompt without adding a record. Test two players, reversed arrival order and tied scores to verify the stated display policy.

    Also inspect the question data. A missing key or an answer code outside the displayed options is an authoring fault, not something the player-response loop should silently repair.

    11 | PERSONALISE THE CONTENT AND FEEDBACK

    Add a new correctly authored question, then rerun the score and percentage tests with the new question count. Keep each answer code aligned with the option’s display position.

    Add a short explanation field to each dictionary and print it after an answer. This makes the quiz more useful for learning, while the collection keeps related question data together.

    Keep a working original before extending. Do not reveal the correct answer before the player responds or reset the scoreboard for every new player.

    12 | REFLECT ON DATA DESIGN

    Explain which objects are lists, dictionaries, tuples and strings. Trace one nested access and one comprehension used to build allowed codes. Describe why scoreboard.append(result) changes the session list but sorted(scoreboard) returns another list.

    Identify limitations: names are not unique identities, results are not saved permanently, and the bank is assumed to be non-empty and valid. These are useful next design questions rather than hidden claims of completeness.

    Finish with a user guide and a test record. The next section introduces functions so you can separate repeated tasks into named reusable units.

    PUT YOUR SKILLS TO WORK

    Use the Section 3 challenges to practise these ideas independently. Work in your Python editor, predict results and keep a short test record.

    Section 3 challenges Python course navigation

    MATCH THE PYTHON TERM TO ITS MEANING

    Terminology

    Terminology

    Question bank

    The ordered list of question records.

    Question record

    A dictionary containing prompt, options and answer.

    Options list

    The displayed answer strings in order.

    Answer code

    A string identifying the correct displayed option.

    Valid choices

    The allowed response codes for one question.

    Player loop

    Repeats completed quiz plays for different users.

    Question loop

    Visits each question for one player.

    Retry loop

    Retains the current question until a choice is allowed.

    Score

    The count of correct accepted responses.

    Percentage

    Score divided by question count, multiplied by 100.

    Scoreboard

    A list of completed name/score result records.

    Result tuple

    An ordered pair keeping a score and name together.

    Tuple ordering

    Compares successive fields until a difference is found.

    Tie policy

    The stated order for equal-score records.

    Display position

    The numbered output position, not necessarily a competition rank.

    Session state

    Data retained during the current program run.

    Authoring assumption

    The question data is non-empty and internally consistent.

    Regression test

    Rechecking known outcomes after modifying the quiz.

    Questions

    Questions

    CHECK YOUR UNDERSTANDING

    Select all correct choices. Each exact set earns one point.

    1. Which describe the question bank?
    2. Which fit the option-code design?
    3. Which score-reset placements are correct?
    4. Which describe scoreboard tuples?
    5. Which describe the stated tie order?
    6. Which are testable outcomes?
    7. Which limitations are explicit?
    8. Which changes need regression checks?

    EXPLAIN AND COMPARE

    Write your answers before revealing each sample.

    1. Describe the quiz’s nested record structure.

    2. Explain why allowed codes are strings.

    3. Explain the question retry loop.

    4. Explain where score is reset.

    5. Explain why a result tuple preserves relationships.

    6. Describe the tie policy.

    7. Suggest tests for zero and full score.

    8. Identify persistence and authoring limits.

    CODE IT | YOUR INDEPENDENT CHALLENGE

    Build the complete quiz. Test wrong answers, retries, tied scores, immediate quit and multiple completed players.

    Work in your Python editor. Keep a working version, explain one design choice and record at least two tests. Use the Learn tab for worked examples before comparing your result.

    Flashcards

    Flashcards

    Click to flip. Select the ideas you need to revisit.

    0 cards selected for revision.

      Selections are kept while this page is open.

      Workbook

      Workbook

      COMING SOON

      The workbook for Project: A Quiz With A Scoreboard is coming soon. Complete the matching task and written questions in your exercise book.