Objects Working Together · capstone
Capstone project: Project: Build a Collaborating Quiz System
Chapter 5 made one
The design you are building
a Quiz has many Questions
a QuizAttempt has a Quiz, and has many Responses
a Response has a Question
a ScoreReport has a QuizAttempt
Four classes, plus Question, which is given to you finished. Nothing points back up, so a Question never learns about a quiz, and a Quiz never learns about an attempt.
What each one owns
| Class | Owns |
|---|---|
Question | Whether a response is correct, and what it is worth. |
Response | That a correct response earns the question’s points. |
QuizAttempt | Which responses were given, plus the quiz title, size, and available points captured when the attempt begins. |
Quiz | Which questions and points exist now, plus applying the pass mark to a supplied score and available total. |
ScoreReport | Turning an attempt into lines of text. |
The temptation this project is built to resist is putting the last three rows in the first class that already has some of the data. Every time you are about to add a
The report needs to show how far through the quiz an attempt is, as "3 of 5 answered". Where does the count of unanswered questions belong?
Rules the grader checks
No class prints.
ScoreReport.lines()returns aof , and only the program at the bottom prints them. No class reaches through another. If you write
attempt.quiz.questions()[0].points, something is asking the wrong object.Quizmentions neither learners nor attempts.Collections handed out to callers cannot be used to change the object that owns them.
An attempt’s title, question count, and available points stay as they were when it began. Later changes to those quiz facts do not rewrite the report. The pass threshold remains a live quiz policy: changing
pass_markcan changepassed, even though the earned score and captured total stay fixed.
This model assumes the caller finishes configuring the quiz before answering and answers each original question at most once. It demonstrates collaboration and snapshots; it does not enforce membership or prevent repeated answers. Keeping a finished quiz version would be a further design decision.
Finishing
When it runs, read your ScoreReport.lines() and ask where each fact came from. Every one should have arrived by asking a neighbor when it needed to be captured, and none should have been worked out twice.
After the checks pass, replace the review questions with three questions on a topic you know and choose a pass mark that makes sense for it. Run one passing and one failing attempt. The collaboration should stay unchanged while the finished quiz becomes recognizably yours.
Task
Complete the four classes so they collaborate without any of them doing another’s work.
Response holds a question and what was given, asks the question once, and snapshots correct, the points available, and earned. Editing a question later must not rewrite an earlier response.
Quiz holds questions and refuses None. It reports question_count and total_points, hands out questions() safely, and answers is_passing(score, available_points=None) against its pass_mark. When no available-points total_points.
QuizAttempt holds a quiz and a learner name. answer(question, given) records a Response and returns whether it was correct. It reports score, correct_count, answered_count, remaining, and passed. When constructed, it captures the quiz’s title, question count, and available points so later edits to those quiz facts cannot rewrite the attempt’s report. The quiz’s pass_mark remains live, so changing that policy can change passed. passed still delegates the decision to the quiz, supplying the captured available points. Expose the captured report facts as read-only quiz_title, question_count, and available_points, so a report need not reach through the attempt.
ScoreReport holds an attempt and returns lines():
Chapter 6 Review: Mina
What does len('cat') return? -> 3 (2 of 2)
Which keyword starts a function? -> class (0 of 3)
2 of 3 answered, 10 points available
Score 2, failed
Assume each original question is answered at most once and the quiz is configured before answering begins.
No class may print. Avoid long attribute chains: ask a direct collaborator for the fact it owns instead of taking its internals apart.