I'm creating a quiz and I try to shuffle answers but one of them keeps repeating. Up to 4 times, sometimes even four (I have 4 answers overall). I have a project deadline soon, please help me. Thank you in advance
`
const questions = [{
question: "What is the name of Ellie's mom?",
answer: ["Jessica", "Monica", "Anna", "Tess"],
correct: "3",
},
{
question: "Around how old is Joel in The Last of Us Part II?",
answer: ["40s", "50s", "60s", "70s"],
correct: "2",
},
{
question: "What is Manny's rank in the WLF?",
answer: ["Sergeant", "Captain", "Lieutenant", "Corporal"],
correct: "3",
},
{
question: "What item does Ellie keep of Sam's that can be seen in her room at the start of The Last of Us Part II?",
answer: ["PS3", "Toy robot", "Cassette player", "Animals of the Past book"],
correct: "2",
},
{
question: "Which game does NOT get referenced in The Last of US Part II?",
answer: ["Deus Ex", "God of War", "Jak and Daxter", "Crash Bandicoot"],
correct: "2",
}
];
/* Getting elements from the DOM */
let headerContainer = document.getElementById("header");
let listContainer = document.getElementById("list");
let submitBtn = document.getElementById("submit");
let startBtn = document.getElementById("start");
let quiz = document.getElementById("quiz");
let score = 0;
let questionIndex = 0;
startBtn.onclick = function () {
startBtn.classList.add("hidden");
quiz.classList.remove("hidden");
document.getElementById("description").classList.add("hidden");
};
function clearPage() {
headerContainer.innerHTML = "";
listContainer.innerHTML = "";
}
clearPage();
showQuestion();
submitBtn.onclick = checkAnswer;
/*A function to show questions*/
function showQuestion() {
/*Show a question*/
let headerTemplate = `<h2 >%title%</h2>`;
let title = headerTemplate.replace('%title%', questions[questionIndex].question);
headerContainer.innerHTML = title;
/*Show answers*/
let answerNumber = 1;
for (var item of questions[questionIndex].answer) {
const questionTemplate = `<li>
<label>
<input value="%number%" type="radio" name="answer">
<span>%answer%</span>
</label>
</li>`;
let answers=questions[questionIndex].answer;
let currentIndex = answers.length, randomIndex;
randomIndex = Math.floor(Math.random() * currentIndex);
let answerText = questionTemplate.replace('%answer%', answers[randomIndex]).replace("%number%", answerNumber);
listContainer.innerHTML = answerText;
answerNumber ;
}
let progress = `<p>${questionIndex 1} out of ${questions.length}</p>`;
document.getElementById("progress").innerHTML = progress;
let scoreBoard = `<p>Score: ${score} out of ${questions.length}</p>`;
document.getElementById("score").innerHTML = scoreBoard;
}
`
I tried a for loop and I tried to shuffle array different ways that I found on the internet but all of them work the way I have now.
CodePudding user response:
Your method would require you to keep track of what questions you used. If you used it, pull another. It could be done, but there are better ways.
Easiest way, generate the array of lis and shuffle that. You also should user template literals the correct way. You are reinventing them by replacing the strings. It does that already!
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;
}
const questions = [{
question: "What is the name of Ellie's mom?",
answer: ["Jessica", "Monica", "Anna", "Tess"],
correct: "3",
},
{
question: "Around how old is Joel in The Last of Us Part II?",
answer: ["40s", "50s", "60s", "70s"],
correct: "2",
},
{
question: "What is Manny's rank in the WLF?",
answer: ["Sergeant", "Captain", "Lieutenant", "Corporal"],
correct: "3",
},
{
question: "What item does Ellie keep of Sam's that can be seen in her room at the start of The Last of Us Part II?",
answer: ["PS3", "Toy robot", "Cassette player", "Animals of the Past book"],
correct: "2",
},
{
question: "Which game does NOT get referenced in The Last of US Part II?",
answer: ["Deus Ex", "God of War", "Jak and Daxter", "Crash Bandicoot"],
correct: "2",
}
];
/* Getting elements from the DOM */
let headerContainer = document.getElementById("header");
let listContainer = document.getElementById("list");
let questionIndex = 0;
function showQuestion() {
headerContainer.innerHTML = `<h2 >${questions[questionIndex].question}</h2>`;
const lis = questions[questionIndex].answer.map((answer, index) =>
`<li>
<label>
<input value="${index}" type="radio" name="answer">
<span>${answer}</span>
</label>
</li>`);
listContainer.innerHTML = shuffle(lis).join('');
}
showQuestion();
<h2 id="header"></h2>
<ul id="list"></ul>
CodePudding user response:
You need, somehow, save (or know) the answers that already come out. Otherwise, you'll create a random number (in your for loop) that might be the same as the previous iteration.
You can create a array with 4 position (answer 1, 2, 3, 4): [1, 2, 3, 4]
let arrayCurrentIndex = [];
for (let index = 0; index < questions[questionIndex].answer.length; index ) {
arrayCurrentIndex.push(index);
}
And then in your for loop you can get a random number from the new array arrayCurrentIndex
randomIndex = arrayCurrentIndex[Math.floor(Math.random() * arrayCurrentIndex.length)];
Now that you have a index, we need to remove the same number of randomIndex
in arrayCurrentIndex
. To prevent the randomIndex
on the next iteration of the loop from being the same as before
let indexToRemove = arrayCurrentIndex.indexOf(randomIndex);
arrayCurrentIndex.splice(indexToRemove, 1);
Like this:
let arrayCurrentIndex = [];
for (let index = 0; index < questions[questionIndex].answer.length; index ) {
arrayCurrentIndex.push(index);
}
/*Show answers*/
let answerNumber = 1;
for (var item of questions[questionIndex].answer) {
const questionTemplate = `<li>
<label>
<input value="%number%" type="radio" name="answer">
<span>%answer%</span>
</label>
</li>`;
let answers=questions[questionIndex].answer;
randomIndex = arrayCurrentIndex[Math.floor(Math.random() * arrayCurrentIndex.length)];
// Remove use number (randomIndex) from arrayCurrentIndex
let indexToRemove = arrayCurrentIndex.indexOf(randomIndex);
arrayCurrentIndex.splice(indexToRemove, 1);
let answerText = questionTemplate.replace('%answer%', answers[randomIndex]).replace("%number%", answerNumber);
listContainer.innerHTML = answerText;
answerNumber ;
}