Submission Details

DrRacket Cheat Sheet
Checking for Errors
Submission FAQ
Autograder FAQ
Late Penalty Waiver

In the last several years, you’ve undoubtedly gotten more experience taking exams and quizzes on computers. But even before then, I bet nearly everyone has taken some kind of personality quiz, whether it be on Buzzfeed, Facebook, etc.. Your job this week is to build an automated quiz taking and scoring system. In this exercise, you’ll be writing structs (with subtyping) and methods. The end product is an automated “quiz” system that gives a score after the user completes the questions.

Getting User Input in ASL As we move into writing code that interacts with a user more, you might find it useful to reference the Racket documentation. While you won't need to actually use the read-line function for this Exercise (we take care of it for you) you will need to use the printf, newline, and with-output-to-string functions (there's a little primer at the top of the assignment template).


Exercise 7 Starter Files


Part 1. Implementing a Quiz

We’re going to take an object-oriented approach to creating an online quiz in ASL. What are quizzes made up of? Questions! So first we need to implementing a basic question struct. While in real life you have quite a bit of flexibility in the design of an object, your struct will need to follow our specifications exactly. The attribute and method names must match exactly, and the attributes have to be written in the listed order.

Note that in the starter code, we have provided an example question (q1) and some tests to be sure that you defined the question struct and its methods properly.

"I Don't Like Wicked."
The built-in example questions are based on the musical Wicked which has a sequel movie-version coming out soon. If you don't like Wicked, we'll try to provide some examples from a Marvel Cinematic Universe based quiz in the assignment below. You're also welcome to create your own questions, just be very careful when defining those questions that they follow the assignment description exactly. Additionally, keep in mind the built-in check-expect are designed to work with the given sample questions so you'll need to update those check-expects to work with your questions.
Example (MCU)
(define q1
  (make-question
   "What is the home country of the Black Panther?"
   "wakanda"
   15))

Activity 1.1: type: question

The attributes of question should be (in the listed order):

Name Type Description
text string the text of the question itself
answer string the correct answer to the question
point-value number the point value of the question

Note: for this part, the answer attribute always stores strings. For parts 2, 3, and 4, the answer attribute will stores numbers instead.


Activity 1.2: methods

Define the methods print-question, check-answer, and get-point for the question type.

  1. print-question : question -> void

    This takes a question object and prints the given question in the following format.

    Question (NN%): TEXT⏎
    

    Here, NN is the points in the point-value attribute, TEXT is the question text in the text attribute, and stands for a newline character at the end (i.e. it’s not an actual arrow character).

    The output of print-question must match the described format, including the spaces, the parentheses, and the colon, etc. The provided check-expect validates the output of print-question for you.

  2. check-answer : question string-or-number -> boolean

    This method takes a question object and a user response, and returns #true if the response equals the answer (use the equal? predicate to test equality here) and #false otherwise.

    You can assume that the type of the user response received by check-answer always equals the type of the answer of the given question. In particular, for this part check-answer always receives a string as the user response. For the next part, (the same) check-answer always receives a number.

  3. get-point : question string-or-number -> number

    This methods takes the same inputs as check-answer and uses check-answer to assess the user response. The get-point method returns point-value when the answer is correct and 0 otherwise.


Activity 1.3: Evaluating Quiz Responses

grade-quiz : (listof question) (listof string-or-number) -> number

Write an ordinary function grade-quiz (not a method!) that evaluates quiz responses. The grade-quiz function takes a list of questions and a list of answers. Then, it uses get-point to calculate and return the overall score. During the process, grade-quiz should print the title Missed Questions and then print the questions for which check-answer is #false using print-question. Additionally, the title and each printed question should be separate by the separator, ===== (that’s 5 equals signs).

Testing Tips
This function is really subtle so make sure all of the following are true:
  1. The function correctly loops (uses for-each) across all the questions in a quiz. You could double check by introducing something like a counter variable or by printing each of the questions as you grade it while debugging
  2. Check that the function correctly sums the total number of available points in a particular quiz.
  3. Make sure it prints out the details of all incorrectly answered questions.
  4. Make sure you use the get-point and check-answer methods to calculate the final score!.
Example (Wicked)
To give an example, running grade-quiz with myquiz1 and the answers (list "Emerald City" "elphaba") should return 20 and print Missed Questions to the screen. If the list of answers is (list "I don't know" "I don't know") instead, the following text should be printed to the screen.
Missed Questions
=====
Question (5%): Where does the Wizard live?
=====
Question (15%): What is the first name of the Wicked Witch of the West?
Example (MCU) If you make myquiz1 like so:
; an example "quiz" (a list of questions)
(define myquiz1 (list (make-question
                       "What does MCU stand for?"
                       "The Marvel Cinematic Universe"
                       5)
                      q1))
To give an example, running grade-quiz with myquiz1 and the answers (list "Marvel Cinematic Universe" "wakanda") should return 20 and print Missed Questions to the screen. If the list of answers is (list "I don't know" "I don't know") instead, the following text should be printed to the screen.
Missed Questions
=====
Question (5%): What does MCU stand for?
=====
Question (15%): What is the home country of the Black Panther?

Part 2. multichoice-question sub-type

A multiple-choice question differs from a regular question in that we need to tell the user what the possible choices are, displaying numerical labels next to each choice, starting at 1. However, it still has some text, answer, and point-value associated with it.

Implement a multichoice-question struct as a subtype of the question struct.

In the starter code, we’ve provided an example question (q2) and some suggested tests to be sure that you defined the multichoice-question struct and its methods properly.

Example (MCU)

  (make-multichoice-question
   "In the post-credits scene of The Avengers movie, what food do the six Avengers go to eat?"
   1  ;; answer
   10 ;; point-value
   4  ;; count
   (list "Shawarma" "Kabobs" "Manakish" "None of the above"))

Activity 2.1: subtype: multichoice-question

Define multichoice-question as a subtype of question.

In addition to the attributes inherited from the question type, multichoice-question should add the following attributes (in the listed order):

Name Type Description
count number the count of choices presented as possible answers to the question
choices (listof string) the possible answers

Note: Unlike question, the multichoice-question type will have numbers in its answer attribute. You can assume that its (inherited) check-answer method will only receive numbers as the user response.

Details on Test 7 in the Template For Test 7, the intent is for you to check that the actual number of choices in the choices attribute matches the count attribute.

Activity 2.2: (override) method: print-question

print-question: multichoice-question -> void

Since multichoice-questions need to be printed differently than questions, we need to override the method print-question in multichoice-question. It should print the given multiple-choice question in the following format.

Question (NN%): TEXT⏎
Enter a number between 1 and M.⏎
1. CHOICE1⏎
2. CHOICE2⏎
...
M. CHOICEM⏎

Here, NN is the points in the point-value attribute, TEXT is the question text in the text attribute, and M is the count of the choices in the count attribute. The output of print-question must match the described format exactly, including the period, the spaces, and the parentheses, etc.

Example Output (Wicked) As an example, the following expression
(print-question
  (make-multichoice-question
   "Which of the following is a song from Wicked?"
   1  ;; answer
   10 ;; point-value
   4  ;; count
   (list "Defying Gravity" "Wait For It" "Tomorrow" "None of the above")))
should print the text
Question (10%): Which of the following is a song from Wicked?
Enter a number between 1 and 4.
1. Defying Gravity
2. Wait For It
3. Tomorrow
4. None of the above
Example Output (MCU) As an example, the following expression
(print-question
  (make-multichoice-question
   "In the post-credits scene of The Avengers movie, what food do the six Avengers go to eat?"
   1  ;; answer
   10 ;; point-value
   4  ;; count
   (list "Shawarma" "Kabobs" "Manakish" "None of the above")))
should print the text
Question (10%): In the post-credits scene of The Avengers movie, what food do the six Avengers go to eat?
Enter a number between 1 and 4.
1. Shawarma
2. Kabobs
3. Manakish
4. None of the above

The provided check-expect validates the output of print-question for you.


Part 3. numeric-question sub-type

A numeric question is displayed just like a question but differs in how we assess the users’ response. That is, we might be a bit forgiving and allow some bit of error in the numeric answer that they give.

In the starter code, we’ve provided an example question (q3) and some suggested tests to be sure that you defined the numeric-question struct and its methods properly.

Example (MCU)
(define q3
  (make-numeric-question
   "What version or mark armor does Tony Stark use during the Battle of Earth featured in Avengers: Endgame?"
   85
   10
   2))

Activity 3.1: subtype: numeric-question

Define numeric-question as a subtype of question.

In addition to the attributes inherited from the question type, numeric-question should add one new attribute:

Name Type Description
epsilon number the allowable difference from the correct answer

Unlike question, the numeric-question type always has numbers in its answer attribute. You can assume that its check-answer method will only receive numbers as the user response.


Activity 3.2: (override) method: check-answer

check-answer : numeric-question number -> boolean

Override the method check-answer in numeric-question and check whether the user response is strictly within within the allowable error from the expected answer. That is, if A is the answer, ε is the allowable difference in the epsilon attribute, and R is the user response, check-answer should output #true if and only if A-ε<R<A+ε.


Part 4. partialcredit-question subtype

A partialcredit question is just like a multiple-choice question but with the ability to assign “partial credit” to some responses. That is, we print a partial-credit question and assess the users’ response the same way as we do for a multiple-choice question, but specifically allow certain answers to receive half of the points.

In the starter code, we’ve provided an example question (q4) and some suggested tests to be sure that you defined the partialcredit-question struct and its methods properly.

Example (MCU)
(define q4
  (make-partialcredit-question
   "After J.A.R.V.I.S were uploaded into Vision, who became the user interface program that Tony Stark uses with his Iron Man suits?"
   3
   15
   4
   (list "e.d.i.t.h" "T.A.D.A.S.H.I" "F.R.I.D.A.Y" "J.O.C.A.S.T.A")
   (list 2 4))) ;; other (partial-credit) answers

Activity 4.1: subtype: partialcredit-question

Define partialcredit-question as a subtype of multichoice-question.

In addition to the attributes inherited from the multichoice-question type, partialcredit-question should add one new attribute:

Name Type Description
others (listof number) the list of answers that should receive half of the points

Activity 4.2: (override) method: get-point

get-point : partialcredit-question number -> number

Override the method get-point in partialcredit-question. If check-answer returns true, get-point should still return full credit. Otherwise, if the user response is any of the choices in the others attribute, get-point should return half of the points. If none of the above is true, get-point returns 0 as usual.


Part 5. Testing your quiz

Once you’ve implemented all of parts 1, 2, 3 and 4, run the line (runquiz myquiz) in the Interactions Window to take the quiz. You should see something like the interaction shown below (this one shows the MCU version).

Screenshot of Final Quiz
Open in Separate Window
Screenshot of final working quiz.
Want to change the title / narrator name? Go for it! You'll see in the screenshot we've changed the "narrator" to "J.A.R.V.I.S." and the title to "Ultimate MCU Fan Quiz". run-quiz is not graded so you should feel free to change either of those strings.

You can leave this line commented or uncommented when you submit; it will not affect the autograder either way.


Double Checking your Work

Make sure you’ve followed the process outlined in the introduction for every function, and that you’ve thoroughly tested your functions for all possible edge cases.

Before turning your assignment in, run the file one last time to make sure that it runs properly and doesn’t generate any exceptions, and all the tests pass. Make sure you’ve also spent some time writing your OWN check-expect calls to test your code.

Assuming they do, submit only your exercise_7.rkt file on Canvas.