Home > Blockchain >  How to generate four choices for users without two choices being the same?
How to generate four choices for users without two choices being the same?

Time:04-22

I'm using an API to create an anime quiz. I'm also using Math.random() to create four choices for the user to click on. But I'm facing two problems. Firstly when the user is presented with the first set of 4 choices, there's a possibility that two are identical. I'd like all four choices to be distinct from each other. Secondly regardless of the user getting the right answer or not I'd like another set of four distinct questions to be generated. I tried to come up with something but it quickly turned into spaghetti code.

const animeApi = "https://anime-facts-rest-api.herokuapp.com/api/v1";
const intro = document.querySelector(".intro");
const anime_picture = document.querySelector(".anime_picture img");
const anime = document.querySelector(".anime");
const questions = Array.from(document.querySelector(".question").children)
const question1 = document.querySelector(".question1");
const question2 = document.querySelector(".question2");
const question3 = document.querySelector(".question3");
const question4 = document.querySelector(".question4");
const question5 = document.querySelector(".question5");
const randomNum1 = Math.floor((Math.random()* 13));
const randomNum2 = Math.floor((Math.random()* 13));
const randomNum3 = Math.floor((Math.random()* 13));
const randomNum4 = Math.floor((Math.random()* 13));
let [counter, score] = [0,0]
let data;

fetch(animeApi)
.then(res => res.json())
.then(response => {
  // response is an object but we need the array in property data
  console.log(response)
  data = response.data;
  console.log(data.length)
  for (let {anime_img} of data) {
    console.log(anime_img)
  }
  // alternative
  //data.forEach(item => console.log(item));
});

intro.addEventListener("click", () => {
  intro.classList.add("hide");
  anime.classList.remove("hide");
  anime.classList.add("show")
  quiz()
});

function quiz() {
  anime_picture.src = data[counter].anime_img;

  question1.innerHTML = data[randomNum1].anime_name;
  question2.innerHTML = data[randomNum2].anime_name;
  question3.innerHTML = data[randomNum3].anime_name;
  question4.innerHTML = data[randomNum4].anime_name;
}


for(var i = 0; i < questions.length; i  ) {
  questions[i].addEventListener("click", userAnswer)
}

function userAnswer(e) {
  let target = e.target.innerHTML
  if(target === data[counter].anime_name) {
    console.log("correct");
    score  
  } else {
    console.log("incorrect");
  }
  update();
}

function update () {
  if(counter < data.length) {
    counter  ;
    quiz();
  }
}
body {
  position: relative;
  display: flex;
  justify-content: center;
  align-content: center;
}

.intro {
  height: 300px;
  width: 300px;
  border: 1px blue solid;
  position: absolute;
  left: 25%;
  text-align: center;
}

.hide {
  visibility: hidden;
}

.show {
  visibility: visible;
}

.anime {
  height: 800px;
  width: 800px;
  border: 1px red solid;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.anime_picture {
  height: 400px;
  width: 400px;
  position: absolute;
}

.question {
  height: 100px;
  width: 100%;
  border: 1px blue solid;
  bottom: 0;
  position: absolute;
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.question > div {
  height: 80px;
  width: auto;
  border: 1px black solid;
  background-color: #ddd;
}

img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

header {
  width: 100%;
  height: 100px;
  border: 1px black solid;
  position: absolute;
  top: 0;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="index.css">
    <title>anime page</title>

  </head>
  <body>
    <div >
      welcome to the anime website
    </div>
    <div >
      <div >
        <img src="" alt="">

      </div>
      <div >
        <div ></div>
        <div ></div>
        <div ></div>
        <div ></div>
      </div>
      <header>anime Quiz</header>

    </div>

  </body>
  <script src="index.js" type="text/javascript"></script>
</html>

CodePudding user response:

The function that assembles the randomly chosen question could also remove that question from its array using the splice array method (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice)

The removed element could be added to a new array to keep track of used questions.

This deals with preventing repeats both in a set of four and in subsequent sets of four.

In the snippet, I've used an array of numbers in proxy for the questions but the logic is the same.

Note the console logs the question array afer each addition, showing the used elements have been removed.

const questions = [1,2,3,4,5,6,7,8,9,10,11,12];
const usedQuestions = [];
const outputField = document.getElementById("output");


function next4() {

  let qPanel = document.createElement('p');
  
  for(let i=0; i<4; i  ) {
         if (questions.length > 0) {
    let index = Math.floor(Math.random()*questions.length);
    qPanel.innerHTML = qPanel.innerHTML   `question ${questions[index]}, `;
    usedQuestions.push(questions[index]);
    questions.splice(index,1);
     } // end if array has length;  
  } // next i question;
outputField.appendChild(qPanel)
console.log(questions)

} // end function next4;
<button onclick="next4()">next set</button>

<div id="output"></output>

The 'full page' link may be needed to see the page and the console.

CodePudding user response:

I little refactored your code and fixed bugs. And now you can get 4 random answers but with guarantee that there is correct answer. Also now the number of answers depends on count of div with class answer:

const animeApi = 'https://anime-facts-rest-api.herokuapp.com/api/v1';
const intro = document.querySelector('.intro');
const anime_picture = document.querySelector('.anime_picture img');
const anime = document.querySelector('.anime');
const answers = [...document.querySelectorAll('.answer')];
let data = [];
let [counter, score] = [0, 0];

fetch(animeApi)
.then(res => res.json())
.then(response => data = response.data);

const getRandomNumber = () => Math.floor(Math.random() * data.length);

intro.addEventListener('click', () => {
  intro.classList.add('hide');
  anime.classList.remove('hide');
  anime.classList.add('show');
  quiz();
});

const getUniqueAnswersNumbers = (count) => {
  const answersNumbers = new Set();
  
  while(!answersNumbers.has(counter)) {
    answersNumbers.clear();
    while (answersNumbers.size < count) answersNumbers.add(getRandomNumber());
  }
  
  return [...answersNumbers];
}

function quiz() {
  anime_picture.src = data[counter].anime_img;
  
  const answersNumbers = getUniqueAnswersNumbers(answers.length);
  
  answers.forEach((answer, i) => answer.innerHTML = data[answersNumbers[i]].anime_name);
}

answers.forEach(answer => answer.addEventListener('click', userAnswer));

function userAnswer(e) {
  const target = e.target.innerHTML;
  
  if(target === data[counter].anime_name) {
    console.log('correct');
      score;
  } else {
    console.log('incorrect');
  }
  
  update();
}

function update () {
  if((counter   1) === data.length) return;
  
    counter;
  quiz();
}
body {
  position: relative;
  display: flex;
  justify-content: center;
  align-content: center;
}

.intro {
  height: 300px;
  width: 300px;
  border: 1px blue solid;
  position: absolute;
  left: 25%;
  text-align: center;
}

.hide {
  visibility: hidden;
}

.show {
  visibility: visible;
}

.anime {
  height: 800px;
  width: 800px;
  border: 1px red solid;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.anime_picture {
  height: 400px;
  width: 400px;
  position: absolute;
}

.answers {
  height: 100px;
  width: 100%;
  border: 1px blue solid;
  bottom: 0;
  position: absolute;
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.answers > div {
  height: 80px;
  width: auto;
  border: 1px black solid;
  background-color: #ddd;
}

img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

header {
  width: 100%;
  height: 100px;
  border: 1px black solid;
  position: absolute;
  top: 0;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="index.css">
    <title>anime page</title>

  </head>
  <body>
    <div >
      welcome to the anime website
    </div>
    <div >
      <div >
        <img src="" alt="">
      </div>
      <div >
        <div ></div>
        <div ></div>
        <div ></div>
        <div ></div>
      </div>
      <header>anime Quiz</header>

    </div>

  </body>
  <script src="index.js" type="text/javascript"></script>
</html>

  • Related