Program: Pop Quiz

Let’s look at a program that asks the user a series of question to which the user replies either true or false. The program will inform the user whether they are correct after each question and give the user a final score at the end. This program could be written in a very literal way where it asks a question, obtains an answer, and uses an if statement to check if the user is right or wrong. The same code could be copied and pasted for every question, like so:

import java.util.Scanner;

public class CrudePopQuiz {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("Q1: Protein is for building muscle. True or False?");
        boolean answer = sc.nextBoolean();
        if (answer == true) {
            System.out.println("Correct!");
        }
        else {
            System.out.println("Wrong.");
        }

        System.out.println("Q2: Cats are nocturnal. True or False?");
        boolean answer = sc.nextBoolean();
        if (answer == false) {
            System.out.println("Correct!");
        }
        else {
            System.out.println("Wrong.");
        }

        System.out.println("Q3: Notes C-E-G make a C minor chord. True or False?");
        answer = sc.nextBoolean();
        if (answer == false) {
            System.out.println("Correct!");
        }
        else {
            System.out.println("Wrong.");
        }
    }
}

Lines 7-14 are a complete question and answer. Line 7 asks a question and line 8 obtains the user’s answer. Line 9 checks whether the user is correct. For this particular question, if the user enters true, they are right, else they are wrong. Lines 16-23 are the same code but altered to suit question 2. Lines 25-32 are the same code again but for question 3.

[Run]
Q1: Protein is for building muscle. True or False?
Answer: true
Correct!
Q2: Cats are nocturnal. True or False?
Answer: true
Wrong.
Q3: Notes C-E-G make a C minor chord. True or False?
Answer: false
Correct!

Does this code give you an icky feeling? The program works but it’s crude, prone to bugs, and harder to modify than it needs to be. For instance, every time a new question needs to be added, the same code needs to be copied, pasted, and altered for each one. Also, if there were 100 questions and question 30 were removed, then all question numbers after 30 would now be wrong and you’d need to amend each one manually. It also encourages code duplication, violating one of the key tenets of programming—DRY (Don’t Repeat Yourself).

So, how do we improve the program? Typically, when you have code you want to repeat, use loops, and when you have lists of things like questions, use arrays (or, better yet, ArrayLists, which we’ll cover in the upcoming sections). First, let’s create two array variables, one to hold the array of questions and another to hold the array of answers:

import java.util.Scanner;

public class PopQuiz {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        String[] questions;
        boolean[] answers;
    }
}

Using an initialiser list for each array, we can add as many questions and answers as desired:

import java.util.Scanner;

public class PopQuiz2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        String[] questions = {
                "The earth is further away from the moon than the sun",
                "Goldfish only have a three second memory",
                "Microwaves have a longer wavelength than ultraviolet",
                "Antibiotics can treat viral infections",
                "Octopuses have three hearts",
                "Trigonometry is the study of triangles",
                "Java is not an OOP language"
        };

        boolean[] answers = {
                false,
                false,
                true,
                false,
                true,
                true,
                false
        };
    }
}

Using an initialiser list, seven questions are added to the questions array (lines 7-15). Naturally, these are in the form of Strings. Correspondingly, seven answers are added to the answers array (lines 17-25) in the form of booleans. For each array, you could put the whole thing on one line, for example:

boolean[] answers = { false, false, true, false, true, true, false };

But I think you’ll agree that having each element on its own line is more legible, especially for the questions array. We will use equivalent indices in both arrays as a way to associate them (e.g. answers[3] is the answer to questions[3]). After both arrays, we’ll loop through the questions array and print out each question:

for (int i = 0; i < questions.length; i++) {
    System.out.printf("\nQuestion %d: %s. True or false?\n", i + 1, questions[i]);
}

The loop takes i from 0 to questions.length (6), repeating 7 times in total. On line 2, the printf method prints each question in a particular format. Remember that the %d and %s in the string are placeholders for subsequent arguments. In this situation, the %d represents the question number; it gets replaced with i + 1. (The reason 1 is added to i is so the question numbers display naturally from 1 to 7, instead of 0 to 6 which is what i actually goes through.) The %s represents the question itself; it gets replaced with questions[i] (the question String). Finally, every question ends with “True or false?”.

[Run]
Question 1: The earth is further away from the moon than the sun. True or false?
Question 2: Goldfish only have a three second memory. True or false?
Question 3: Microwaves have a longer wavelength than ultraviolet. True or false?
Question 4: Antibiotics can treat viral infections. True or false?
Question 5: Octopuses have three hearts. True or false?
Question 6: Trigonometry is the study of triangles. True or false?
Question 7: Java is not an OOP language. True or false?

Now, let’s add some more code to the loop that prompts the user for an answer after each question and tells them if they’re right or wrong:

for (int i = 0; i < questions.length; i++) {
    System.out.printf("\nQuestion %d: %s. True or false?\n", i + 1, questions[i]);
    System.out.print("Answer: ");
    boolean userAnswer = sc.nextBoolean();

    if (userAnswer == answers[i]) {
        System.out.println("Correct!");
    }
    else {
        System.out.println("Incorrect! It's " + answers[i] + ".");
    }
}

Line 3 asks the user for an answer. Line 4 obtains the user’s response. Line 6 checks if the user’s answer is correct by comparing it to the answer in the answers array. If true, line 7 prints “Correct!”. Else, line 10 prints “Incorrect!”.

[Run]
Question 1: The earth is further away from the moon than the sun. True or false?
Answer: false
Correct!
Question 2: Goldfish only have a three second memory. True or false?
Answer: true
Incorrect! It's false.
Question 3: Microwaves have a longer wavelength than ultraviolet. True or false?
Answer: true
Correct!
Question 4: Antibiotics can treat viral infections. True or false?
Answer: false
Correct!
Question 5: Octopuses have three hearts. True or false?
Answer: false
Incorrect! It's true.
Question 6: Trigonometry is the study of triangles. True or false?
Answer: true
Correct!
Question 7: Java is not an OOP language. True or false?
Answer: false
Correct!

Let’s also inform the user of their final score when the quiz ends.

int finalScore = 0;

for (int i = 0; i < questions.length; i++) {
    System.out.printf("\nQuestion %d: %s. True or false?\n", i + 1, questions[i]);
    System.out.print("Answer: ");
    boolean userAnswer = sc.nextBoolean();

    if (userAnswer == answers[i]) {
        System.out.println("Correct!");
        finalScore++;
    }
    else {
        System.out.println("Incorrect! It's " + answers[i] + ".");
    }
}

System.out.printf("\nYour final score is %d out of %d (%.1f%%).", finalScore, questions.length, ((double)finalScore / questions.length) * 100);
[Run]
...
Question 5: Octopuses have three hearts. True or false?
Answer: false
Incorrect! It's true.
Question 6: Trigonometry is the study of triangles. True or false?
Answer: true
Correct!
Question 7: Java is not an OOP language. True or false?
Answer: false
Correct!
Your final score is 5 out of 7 (71.4%).

Only lines 1, 10, and 17 are new. Line 1 declares a variable finalScore to hold the user’s final score. Line 10 increases finalScore by 1 every time the user gets a question right. When the loop ends (meaning the quiz is over), line 17 prints some interesting information for the user to see. In the sample output, the user got 5 out of 7 correct, which results in the following line of output:

Your final score is 5 out of 7 (71.4%).

Let’s go through that particular example. Line 17 starts with the text Your final score is %d. The %d is replaced with finalScore (5). After, it reads out of %d. This %d is replaced with questions.length (7). Then it reads (%.1f%%). This is actually two separate format specifiers, more easily distinguished when highlighted: (%.1f%%). The first, in blue, is a placeholder for the 4th argument, that is ((double)finalScore / questions.length) * 100. This code calculates the user’s percentage. You can see it simply divides their score by the number of questions (5 / 7) and then multiplies it by 100 to get the percentage. However, both finalScore and questions.length are ints. Remember that integer division results in an integer but we’d prefer the percentage to show as a decimal, which is why finalScore is cast to a double before the division takes place. The .1 in the format specifier rounds the result to 1 decimal place so we get 71.4 as the output and not 71.428571. Now for the part highlighted in orange. Since we’re dealing with a percentage, we want a percent sign (%) after the number. The problem is that, within the content of printf statements, Java interprets percent signs as format specifiers. So how do we tell Java to treat it as a normal character like any other? Simply use two percent signs (%%). This gets translated to a single, printable percent sign character, as can be seen from the output. The same is also true for backslashes. You can’t simply write a backslash in a String because Java will try to interpret it as the beginning of an escape sequence, such as \n. Therefore, if you want a normal backslash character, you need to write \\.

Leave a Reply

Your email address will not be published. Required fields are marked *