0%

More Expressive Functions · capstone

Capstone project: Project: Configurable Scoring and Reports

Across this chapter, you made easier to understand and adjust without introducing classes. You added useful defaults, named important choices, represented a missing with None, documented rules, separated calculation from printing, and passed a function as a choice.

This project brings those ideas back to the quiz engine from Chapter 1. That version used one fixed comparison rule and one fixed report. The revised version will still use , but its functions will allow the surrounding code to choose more of their behavior.

The work moves through a short sequence:

  1. select a function for comparing answers;

  2. calculate the score and optional bonus;

  3. build a report from the returned score.

You will reuse the chapter’s ideas along the way:

  • a function value selects the answer-matching behavior;

  • a default makes exact matching the common choice;

  • a keyword-only bonus makes an important adjustment explicit;

  • None distinguishes an omitted report note;

  • type hints and docstrings state public promises;

  • pure functions return results instead of printing.

The supplied matching functions

Exact matching preserves every character:

def exact_match(response, expected):
    return response == expected

Flexible matching cleans both values:

def flexible_match(response, expected):
    return response.strip().lower() == expected.strip().lower()

score_attempts should receive one of these functions and call it for each attempt.

The data contract

Each attempt dictionary has three keys:

{
    "response": " DEF ",
    "expected": "def",
    "points": 2,
}

When the selected matcher returns True, add that attempt’s points. Add the keyword-only bonus once after checking all attempts.

A pure report builder

build_report should return two lines:

Practice: 6/6
Perfect score!

When note is omitted, choose "Perfect score!" for a full score and "Keep practicing." otherwise. Preserve a supplied note exactly.

Put the scoring pipeline in order:

Drag the options into order, or use the arrow buttons.

  • Receive attempts and a matching function.

  • Add points for successful matches.

  • Call the matching function for each response and expected answer.

  • Return the score.

  • Pass the score to a separate report-building function.

  • Add the one-time bonus.

Make the functions work with new data

The hidden checks use different attempts and may provide another matching function. Write each function from its stated rules rather than from the values in the visible example.

Keep this solution function-based. Chapter 4 will revisit the same quiz domain after this procedural version is working clearly.

Task

Complete score_attempts and build_report.

score_attempts:

  • Keep matcher=exact_match as the default.

  • Keep bonus keyword-only.

  • Keep the provided docstring.

  • Call matcher(response, expected) for each attempt.

  • Add matching points, then add bonus once.

  • Return the number without printing.

build_report:

  • Keep the provided type hints on score, total, label, and the , plus the docstring.

  • Choose a note only when note is None.

  • Use "Perfect score!" for a full score and "Keep practicing." otherwise.

  • Return label: score/total, a newline, and the note.

The visible example should report a perfect score after flexible matching and a one-point bonus.