Quiz Generator in React

Using Random Number Generator and Recursion to create Questions from a db.json

Andrew Forest
5 min readJan 6, 2023

Introduction:

Using the A Song of Ice and Fire API, which can be found here: https://anapioficeandfire.com/?ref=apilist.fun , I have created a website that creates a quiz on the characters of the popular show Game of Thrones. The questions are randomly generated from the characters json Database, which contains an array of character objects. The character object can be seen below:

    {
"id": 30,
"Name": "Jeor Mormont",
"Image": "./CharacterImages/Jeor Mormont.png",
"IsFemale": false,
"Culture": "Northmen",
"Titles": [
"Lord of Bear Island (formerly)",
"Lord Commander of the Night's Watch"
],
"Aliases": [
"The Old Bear"
],
"Born": "In 230 AC",
"Died": "In 299 AC, at Craster's Keep",
"Father": null,
"Mother": null,
"Spouse": null,
"Children": [],
"Allegiances": [
271
],
"Books": [
1,
2,
3,
5,
8
],
"PovBooks": [],
"PlayedBy": [
"James Cosmo"
],
"TvSeries": [
"Season 1",
"Season 2",
"Season 3"
]
}

From this object, the quiz can select from “Name”, “Titles”, “Aliases”, or “PlayedBy” to create a question about that character. The quiz also takes information from other characters to generate wrong answers for a multiple choice format. The end product looks like the following image:

Variables:

To start, first define the variables needed for each question. Since the question will have an image of a character, a question string, a correct answer, and 4 answer choices, there should be 4 variables to create. Since this application is being built in react, the variables will be created using useState and passed down to a child component. The code will look something like this:

function Quiz({characters}) { 
const [answers, setAnswers] = useState({
answer1:"answer1",
answer2:"answer2",
answer3:"answer3",
answer4:"answer4"
});

const [character, setCharacter] = useState({});

const [question, setQuestion] = useState("Show question here");

const [correctAnswer, setCorrectAnswer] = useState("");

return (
<Question character={character} answers={answers} correctAnswer={correctAnswer} question={question} />
)
}

Because the question will update every time the user submits an answer, the variables will be declared using useState so the page renders properly.

Each variable has been given a generic starting value that will change once the user starts the quiz, the place holders are to show what data type each variable will be.

characters: array of objects passed to this component as a prop, where it was previously fetched from the json database

answers: object containing 4 strings pertaining to 4 multiple choice answers

character: object that will be pulled from characters array

question: the string that will be displayed for the user

correctAnswer: the string that will be used to compare the users response to see if the user is correct

Functions:

Now that we have some variables to work with, it’s time to create some functions to generate the quiz prompts. The first function will create a random integer between a given min and max value.

Random Integer Function:

    const getRndInteger = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) ) + min;
}

This function can be found at https://www.w3schools.com/js/js_random.asp , along with other random number functions and their explanations/examples.

New Question Function:

This function will be the main function called to generate a question, and will use other functions not yet created.

const newQuestion = () => {
const newCharacter = characters[getRndInteger(0,characters.length - 1)]

const newQuestionType = getRndInteger(1,4)

const newQuestionString = newQuestionPhrase(newQuestionType)

const newAnswer = {
answer1: getWrongAnswer(newQuestionType),
answer2: getWrongAnswer(newQuestionType),
answer3: getWrongAnswer(newQuestionType),
answer4: getWrongAnswer(newQuestionType)
}
const ca = getCorrectAnswer(newCharacter, newQuestionType)
newAnswer[`answer${getRndInteger(1,4)}`] = ca
}

newCharacter pulls a single character object out of the characters array randomly by using the getRndInteger function to create a random integer to plug into the [] of the array to get a single object. Using 0 and characters.length — 1 covers the entire length of the array so every character object is available without moving past the array’s length. Then a random integer between 1–4 is given to newQuestionType to determine which question will be selected in the next Function.

New Question Phrase Function:

newQuestionPhrase will return a string containing the question sentence the user will be asked to answer.

const newQuestionPhrase = (questionType) => {
switch (questionType) {
case 1:
return (<p>What is this characters name?</p>)
break;
case 2:
return (<p>Which Title does this Character Hold?</p>)
break;
case 3:
return (<p>What nicknames/aliases belongs to this character?</p>)
break;
case 4:
return (<p>What actor/actress is this character played by?</p>)
break;
default:
return (<p>Error</p>)
break;
}
}

By using a switch statement, this function easily returns the desired question string based on the random number passed into the function’s parameter.

Next, newAnswers will be declared and given wrong answers to fill up the multiple choice answer options by using the getWrongAnswer function.

Get Wrong Answer Function:

To get a wrong answer this function will pull the data from the key pertaining to the question type created using the getRndInteger and stored in the variable newQuestionType, which is then passed to the function parameter. A switch statement is used to return the correct keys information.

const getWrongAnswer = (questionType) => {
const ranNum = getRndInteger(0,characters.length - 1)

switch (questionType) {
case 1:
return characters[ranNum].Name
break;
case 2:
if(characters[ranNum].Titles.length===0 || characters[ranNum].Titles[0]===""){
return getWrongAnswer(questionType)
}
else{
return characters[ranNum].Titles[getRndInteger(0,characters[ranNum].Titles.length - 1)]
}
break;
case 3:
if(characters[ranNum].Aliases.length===0 || characters[ranNum].Aliases[0]===""){
return getWrongAnswer(questionType)
}
else{
return characters[ranNum].Aliases[getRndInteger(0,characters[ranNum].Aliases.length - 1)]
}
break;
break;
case 4:
return characters[ranNum].PlayedBy[0]
break;
default:
return "Error"
break;
}
}

Some of the data in the characters object may not contain any data, to check for this, a simple if else statement is used. If the key does not have any data, the function will be called again to get a new character, that may have data. This recursion will occur until suitable data is found.

Finally, the correct answer will be created and placed at random in the answers object. To do this, the getCorrectAnswer function will be created.

Get Correct Answer Function:

getCorrectAnswer works similarly to the getWrongAnswer function, the only difference is that there is no recursion and the function will return “Error” instead of finding a new answer.

const getCorrectAnswer = (character, questionType) => {
switch (questionType) {
case 1:
return character.Name
break;
case 2:
if(character.Titles.length===0 ){
return "Error"
}
else{
return character.Titles[getRndInteger(0,character.Titles.length - 1)]
}
break;
case 3:
if(character.Aliases.length===0){
return "Error"
}
else{
return character.Aliases[getRndInteger(0,character.Aliases.length - 1)]
}
break;
case 4:
return character.PlayedBy[0]
break;
default:
return "Error"
break;
}
}

Last, the correct answer will be placed into the newAnswers object at random, and the useState variables will be updated.

Final New Question Function:

const newQuestion = () => {
const newCharacter = characters[getRndInteger(0,characters.length - 1)]

const newQuestionType = getRndInteger(1,4)

const newQuestionString = newQuestionPhrase(newQuestionType)

const newAnswer = {
answer1: getWrongAnswer(newQuestionType),
answer2: getWrongAnswer(newQuestionType),
answer3: getWrongAnswer(newQuestionType),
answer4: getWrongAnswer(newQuestionType)
}

const ca = getCorrectAnswer(newCharacter, newQuestionType)
newAnswer[`answer${getRndInteger(1,4)}`] = ca

setCharacter(newCharacter)
setAnswers(newAnswer)
setQuestion(newQuestionString)
setCorrectAnswer(ca)
}

To see full application, go to https://github.com/Andrew-Forest1/Project2

--

--

Andrew Forest

I am an aspiring software Engineer working my way through the Flatiron coding bootcamp.