如何在两个选择不相同的情况下为用户生成四个选择?

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

我正在使用 API 创建动漫测验。我还使用 Math.random() 创建四个选项供用户单击。但我面临两个问题。首先,当向用户呈现第一组 4 个选择时,有可能其中两个是相同的。我希望所有四个选择都彼此不同。其次,无论用户是否获得正确答案,我都希望生成另一组四个不同的问题。我试图想出一些东西,但它很快变成了意大利面条代码。

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>

组合随机选择问题的函数也可以使用 splice 数组方法 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice)

从其数组中删除该问题

删除的元素可以添加到新数组中以跟踪使用过的问题。

这涉及防止在四人一组和随后的四人一组中重复。

在代码片段中,我使用了一组数字来代替问题,但逻辑是相同的。

请注意,每次添加后控制台都会记录问题数组,显示已使用的元素已被删除。

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>

可能需要 'full page' link 才能查看页面和控制台。

我几乎没有重构您的代码并修复了错误。现在你可以获得 4 个随机答案,但保证有正确答案。此外,现在答案的数量取决于 div 和 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>