Skip to content
Advertisement

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

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 class="intro">
      welcome to the anime website
    </div>
    <div class="anime hide">
      <div class="anime_picture">
        <img src="" alt="">

      </div>
      <div class="question">
        <div class="question1"></div>
        <div class="question2"></div>
        <div class="question3"></div>
        <div class="question4"></div>
      </div>
      <header>anime Quiz</header>

    </div>

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

Advertisement

Answer

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 class="intro">
      welcome to the anime website
    </div>
    <div class="anime hide">
      <div class="anime_picture">
        <img src="" alt="">
      </div>
      <div class="answers">
        <div class="answer answer1"></div>
        <div class="answer answer2"></div>
        <div class="answer answer3"></div>
        <div class="answer answer4"></div>
      </div>
      <header>anime Quiz</header>

    </div>

  </body>
  <script src="index.js" type="text/javascript"></script>
</html>
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement