0%

Objects Working Together · capstone

Capstone project: Project: Build a Collaborating Quiz System

Chapter 5 made one trustworthy. This chapter made several objects work together without any one of them knowing too much. The project puts the whole arrangement in place.

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

ClassOwns
QuestionWhether a response is correct, and what it is worth.
ResponseThat a correct response earns the question’s points.
QuizAttemptWhich responses were given, plus the quiz title, size, and available points captured when the attempt begins.
QuizWhich questions and points exist now, plus applying the pass mark to a supplied score and available total.
ScoreReportTurning 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 , check the table.

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 a of , 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.

  • Quiz mentions 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_mark can change passed, 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 is supplied, it uses its current 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.