Spelchan.com Logo

From Scratch Web Games: A Beginners Guide to Game Development using HTML, CSS, and JavaScript

Chapter 5.18: Trivia Project Solution

The first step in any trivia game is coming up with questions. As it is easiest to create questions for a topic you are familiar with, I opted to go with the first four chapters of this book. As stated by the requirements, there should be 5 types of questions so I had one of each type of question for each of the first four chapters of the book. While it would not be overly difficult to generate the form in JavaScript, just like we did with the table in chapter 4, I opted to take the easier route and hand code my questions. As all the chapters have similar form code, I will only show one of the chapter’s code so you can see how the different types of questions were laid out in HTML.

One important feature that I wanted was for there to be check marks for correct answers and Xs for incorrect answers once the quiz has been completed. This is done by having a span section before each question that will hold the checkmark or X. Some simple utility functions take in the label used for the mark and sets the contents and colors appropriately. We are simply using existing Unicode characters for the symbols so no images need to be loaded, but if we wanted a more custom look for our checkmarks we could easily have used an image tag instead of a span and change the image being used to the appropriate image.

function setCheckmark(idLabel) {
let markSpan = document.getElementById(idLabel);
markSpan.style.color = "green";
markSpan.innerHTML = "✔ ";
}

function setXMark(idLabel) {
let markSpan = document.getElementById(idLabel);
markSpan.style.color = "red";
markSpan.innerHTML = "✖ ";
}

The true/false questions can be a simple group of radio buttons. You will notice that to support marking the question we have the section have an overall label, for the final mark of the question. Each radio button is labelled with the same base label followed by an extended label (letters, but anything would work).

<legend>Chapter 1</legend>
<p><span id="c1q1mark"></span>The purpose of this book is to give the programming foundation necessary for a future book on?</p>
<input type="radio" name="c1q1" id="c1q1a" value="c1q1a">
<label for="c1q1a">Learning TypeScript</label><br>
<input type="radio" name="c1q1" id="c1q1b" value="c1q1b">
<label for="c1q1b">Writing an Operating System</label><br>
<input type="radio" name="c1q1" id="c1q1c" value="c1q1c">
<label for="c1q1c">Writing a Game Engine</label><br>
<input type="radio" name="c1q1" id="c1q1d" value="c1q1d">
<label for="c1q1d">Creating our AI Overlord</label><br>

The code for checking the answer is very simple as all we need to do is see if the selected radio button matches the answer we are expecting. The base label is used for the checkmark by adding the mark extension to the label, while we take advantage of the querySelector function for determining which label is checked. If the checked label is not null, as it is possible for the user to not select an item, and the answer id matches our concatenation of the base label and our correct extension then we set the checkmark and return 1 to indicate they got the question correct. If the answer is not correct, we default to setting the X mark and return 0 for the score.

function processMultipleChoice(baseLabel, correct) {
let ans = document.querySelector(`input[name=${baseLabel}]:checked`);
if (ans != null) {
if (ans.id===(baseLabel+correct) ) {
setCheckmark(baseLabel+"mark");
return 1;
}
}
setXMark(baseLabel+"mark");
return 0;
}

Having a section where players select multiple answers, with some being correct while others being incorrect is a bit trickier to implement. First, because an answer has multiple correct or incorrect answers, each checkbox needs to have a mark span beside it. We also need a way of knowing if the answer is correct or not. This could be done in a similar way to how we did it with the multiple-choice above and have the mark method passed the information, but as the value of checkboxes do not need to be unique, we can simply build the marking information right into the form. Checkboxes with a value of T are expected to be checked, while checkboxes with a value of F are expected to remain unchecked.

<p>The tools needed for creating HTML pages are (select all that are required):</p>
<span id="c1q2mark0"></span>
<input type="checkbox" name="c1Q2a" id="c1q2_0" value="T">
<label for="c1q2_0">Text editor</label><br>
<span id="c1q2mark1"></span>
<input type="checkbox" name="c1Q2b" id="c1q2_1" value="F">
<label for="c1q2_1">Word processor</label><br>
<span id="c1q2mark2"></span>
<input type="checkbox" name="c1Q2c" id="c1q2_2" value="F">
<label for="c1q2_2">Spreadsheet</label><br>
<span id="c1q2mark3"></span>
<input type="checkbox" name="c1Q2d" id="c1q2_3" value="T">
<label for="c1q2_3">Browser</label><br>

For checking the multiple correct we need to know the base label and for convenience the number of choices. It is possible to find the number of choices with code, but as I had this information it was easier to simply pass this value. We then loop through all the labels and process each answer separately while counting the number of correct answers. Once we know how many are correct, we normalize the score by dividing the number of correct answers by the total number of answers that are part of the question.

function processMultipleCorrect(baseLabel, numChoices) {
let score = 0;
for (let i = 0; i < numChoices; ++i) {
let cbx = document.getElementById(baseLabel+"_"+i);
let correct = (cbx.value==="T") ? cbx.checked : ! cbx.checked;
if (correct) {
score++;
setCheckmark(baseLabel+"mark"+i);
} else {
setXMark(baseLabel+"mark"+i)
}
}
return score / numChoices;
}

Ordering is a bit more of a pain to prepare. Each line is a select box, with the options being the list to be ordered. This means a lot of code duplication. I opted to always have each option be the first option in the list, bur if you wanted all possible answers represented, you could simply take advantage of the selected attribute and assign each line a different answer. The correct order is the value of the option. As each line is part of the answer, we need a mark by each line.

<p>What order did we cover the three technologies we cover in this book?</p>
<span id="c1q3mark0"></span><select id="c1q3_0">
<option value="1">CSS</option>
<option value="0">HTML</option>
<option value="2">JavaScript</option>
</select><br>
<span id="c1q3mark1"></span><select id="c1q3_1">
<option value="1">CSS</option>
<option value="0">HTML</option>
<option value="2">JavaScript</option>
</select><br>
<span id="c1q3mark2"></span><select id="c1q3_2">
<option value="1">CSS</option>
<option value="0">HTML</option>
<option value="2">JavaScript</option>
</select>

As with the multiple-answers question, we are being lazy and providing the number of answers but could have had code to figure this out. We loop through the answers, knowing that the value of the option should be the same as the select box that we are processing. This results in the score and setting of checkmarks. Once marked, we normalize the score by dividing the number of correctly positioned items by the number of choices.

function processOrdering(baseLabel, numChoices) {
let score = 0;
for (let i = 0; i < numChoices; i++) {
let op = document.getElementById(baseLabel+"_"+i);
// noinspection EqualityComparisonWithCoercionJS
if (op.value == i) {
score++;
setCheckmark(baseLabel+"mark"+i);
} else {
setXMark(baseLabel+"mark"+i)
}
}
return score / numChoices;
}

The fill-in-the-blank style of question is probably the easiest to set up as it is simply a text input box.

<p><span id="c1q4mark"></span>The I in IDE stands for
<input type="text" id="c1q4">.
</p>

My approach to checking the fill-in-the-blank is not the best approach, as I am assuming just a single correct answer. If the mark matches, then you have the correct answer otherwise you do not. A better approach would be to have an array of answers, but as I haven’t covered arrays yet, the less accurate approach was used. We will be looking at arrays in chapter 7.

function processFillInTheBlank(baseLabel, answer) {
let ans = document.getElementById(baseLabel).value;
if (ans.trim().toUpperCase() === answer.toUpperCase()) {
setCheckmark(baseLabel+"mark");
return 1;
}
setXMark(baseLabel+"mark")
return 0;
}

Finally, the number entry option is also very easy to set up in HTML as it is just a number input box.

<p><span id="c1q5mark"></span>This book is expected to have how many chapters?
<input type="number" id="c1q5">.
</p>

Checking the answer is also easy as we just see if the number matches the answer. The number questions I wrote all have precise answers, if this was not the case, a more flexible approach would be to have a range of acceptable numbers.

function processNumeric(baseLabel, answer) {
let ans = document.getElementById(baseLabel).value;
// noinspection EqualityComparisonWithCoercionJS
if (ans == answer) {
setCheckmark(baseLabel+"mark");
return 1;
}
setXMark(baseLabel+"mark")
return 0;
}

With all the questions finished, we need to score the answers. This is simply calling the processing method for each question. Once you have the final score you can then put the final results onto the page.

function processChapter1() {
let count = processMultipleChoice("c1q1", "c");
count += processMultipleCorrect("c1q2", 4);
count += processOrdering("c1q3", 3);
count += processFillInTheBlank("c1q4", "INTEGRATED");
count += processNumeric("c1q5", 11);
return count;
}

That is it for this chapter. In the next chapter we will be looking at the layout capabilities of CSS.

Chapter contents

Chapter 5 Contents

5.1 Forms Cheat Sheets

This chapter's summary cheat sheet.

5.2 The client-server model

How forms are traditionally used.

5.3 The Form tag

How to set up a form in HTML.

5.4 Inputting text

Getting text input from the user.

5.5 Specialized text formats

Making your input fields more specific and semantic.

5.6 Form cosmetics

Making forms look more like printed forms.

5.7 checkboxes & radio buttons

How to use Checkboxes and Radio buttons.

5.8 Numbers and Dates

Using numbers and dates gives your user better GUI controls.

5.9 special purpose input types

The reset, button, image, color, and file input types.

5.10 Option Select

The select element lets users select options from a drop-down list.

5.11 Data Lists

The datalist elements lets you create pull-down lists for input elements.

5.12 Output

Displaying values in a form.

5.13 dialog box concepts

Built in dialog boxes and pre-dialog tag handmade dialogs.

5.14 using dialog boxes

The <dialog> tag and using it to create dialog boxes.

5.15 Validating forms

Review of validating forms in HTML.

5.16 JavaScript Validation

How to use JavaScript to prevent invalid forms from being submitted.

5.17 Project: Trivia

Chapter project: Trivia game

5.18 Trivia Project Solution

Solution for the Trivia gaame

← previous section
Chapter Project: Trivia
next chapter →
Coming in 2025
Table of Contents