I'm pulling 10 random questions from an API but currently, the correct answer is set to always be 'D'. I'm struggling to find a way to randomize the answers so that the correct answer is not always 'D' or any other option I set in the code. The JSON is an array of objects but because incorrect_answers is an inner array within the object separate from correct_answer, this is where I'm getting confused. If I shuffle the inner array, that just shuffles options A, B and C. D remains a separate property outside of that that inner array.
Hope someone can help. Thanks in advance. see app screenshot here
This is a sample from the JSON
{
"response_code": 0,
"results": [
{
"category": "Entertainment: Video Games",
"type": "multiple",
"difficulty": "easy",
"question": "What is the most expensive weapon in Counter-Strike: Global Offensive?",
"correct_answer": "Scar-20/G3SG1",
"incorrect_answers": [
"M4A1",
"AWP",
"R8 Revolver"
]
},
{
"category": "Entertainment: Cartoon & Animations",
"type": "multiple",
"difficulty": "easy",
"question": "Who is the only voice actor to have a speaking part in all of the Disney Pixar feature films? ",
"correct_answer": "John Ratzenberger",
"incorrect_answers": [
"Tom Hanks",
"Dave Foley",
"Geoffrey Rush"
]
}
}
This is my code so far
const main = () => {
let score = 0;
let questionCounter = 0;
let availableQuestions = [];
let currentQuestion = {};
// target DOM elements
const question = document.querySelector(".question-container");
const choices = document.querySelectorAll(".choice-txt");
const selection = document.querySelectorAll(".choice-container");
// API endpoint
const endPoint = `https://opentdb.com/api.php?amount=10&difficulty=easy&type=multiple`;
// fetch data from the API
fetch(endPoint)
.then((res)=>{
return res.json();
})
.then((json)=>{
question.innerHTML = `<p>
${json.results[0].question}
</p>`
// populate the 4 answer options
// currently the correct answer is always D
choices[0].innerText = `${json.results[0].incorrect_answers[0]}`
choices[1].innerText = `${json.results[0].incorrect_answers[1]}`
choices[2].innerText = `${json.results[0].incorrect_answers[2]}`
choices[3].innerText = `${json.results[0].correct_answer}`
})
.catch((err)=>{
console.log(`An error occured ${err}`);
})
selection[0].addEventListener("click",()=>{
console.log(`Answer "A" selected`)
})
selection[1].addEventListener("click",()=>{
console.log(`Answer "B" selected`)
})
selection[2].addEventListener("click",()=>{
console.log(`Answer "C" selected`)
})
selection[3].addEventListener("click",()=>{
console.log(`Answer "D" selected`)
})
}
main();
For this, you need to put together correct/incorrect answers into an object array. (Making normalization)
I used the Fisher-Yates shuffle. Take a look at here
Shuffling Part:
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
Also, I made improvements to the code for readability.
Normalization Part:
// fetch data from the API
fetch(endPoint)
.then((res) => {
return res.json();
}).then((json) => {
question.innerHTML =
`<p>
${json.results[0].question}
</p>`
let answers = json.results[0].incorrect_answers.map(f => {
return {
isCorrect: false,
text: f
}
});
answers.push({
isCorrect: true,
text: json.results[0].correct_answer
});
// populate the shuffled 4 answer options
shuffle(answers).forEach((answer, index) => {
choices[index].innerText = `${answer.text}`
})
})
.catch((err) => {
console.log(`An error occured ${err}`);
})
Test Part:
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
// Create sample data.
const results = [
{
"category": "Entertainment: Video Games",
"type": "multiple",
"difficulty": "easy",
"question": "What is the most expensive weapon in Counter-Strike: Global Offensive?",
"correct_answer": "Scar-20/G3SG1",
"incorrect_answers": [
"M4A1",
"AWP",
"R8 Revolver"
]
},
{
"category": "Entertainment: Cartoon & Animations",
"type": "multiple",
"difficulty": "easy",
"question": "Who is the only voice actor to have a speaking part in all of the Disney Pixar feature films? ",
"correct_answer": "John Ratzenberger",
"incorrect_answers": [
"Tom Hanks",
"Dave Foley",
"Geoffrey Rush"
]
}
];
// Putting wrong answers
let answers = results[0].incorrect_answers.map(f => {
return {
isCorrect: false,
text: f
}
});
// Also putting correct answer
answers.push({
isCorrect: true,
text: results[0].correct_answer
});
//Logging shuffled answers
shuffle(answers).forEach((answer, index) => {
console.log(answer);
})