游戏逻辑错误,用户选择了正确的选项,但没有得到积分。

huangapple go评论69阅读模式
英文:

Game logic error , users choses correct choices but donst get point

问题

这个游戏是一个乘法游戏,玩家有4个选项可供选择,例如4*5,用户必须在20和另外3个错误答案之间进行选择,但一旦用户选择了正确的选项,得分不会增加,尽管正确答案===用户选择,我是JavaScript新手,所以请给出为什么逻辑不起作用的详细解释。
这是HTML

<nav>
  <div class="reset utilites">重置</div>
  <div class="score utilites">
    分数: <span class="ScoreNumber">0</span>
  </div>
  <div class="highScore utilites">
    最高分: <span class="highScoreNumber">0</span>
  </div>
</nav>
<section>
  <div class="choices" id="1">
    &#128682;
    <div class="answer answer1">答案</div>
  </div>
  <div class="choices" id="2">
    &#128682;
    <div class="answer answer2">答案</div>
  </div>
  <div class="choices" id="3">
    &#128682;
    <div class="answer answer3">答案</div>
  </div>
  <div class="choices" id="4">
    &#128682;
    <div class="answer answer4">答案</div>
  </div>
</section>
<div class="question">---</div>

你的JavaScript代码已经包括了游戏逻辑,主要用于处理用户的选择和分数计算。如果你需要解释代码中的具体逻辑,请提出具体问题,我将尽力解答。

英文:

This Game is a multiplication game where player gets 4 options to choose from for example 4*5 and user has to choose between 20 and 3 other wrong answers but once user selects the right option it doesn't increment the score although correct answer === users choice, i am new to JavaScript so please give full explanation to why the logic isn't working .
This is the HTML

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

&quot;use strict&quot;;

const resetBtn = document.querySelector(&quot;.reset&quot;);
const Navscore = document.querySelector(&quot;.ScoreNumber&quot;);
const scoreToReset = document.querySelector(&quot;.score&quot;);
const question = document.querySelector(&quot;.question&quot;);
const highScoreNumber = document.querySelector(&quot;.highScoreNumber&quot;);
const choices1 = document.getElementById(&quot;1&quot;);
const choices2 = document.getElementById(&quot;2&quot;);
const choices3 = document.getElementById(&quot;3&quot;);
const choices4 = document.getElementById(&quot;4&quot;);
const answer1 = document.querySelector(&quot;.answer1&quot;);
const answer2 = document.querySelector(&quot;.answer2&quot;);
const answer3 = document.querySelector(&quot;.answer3&quot;);
const answer4 = document.querySelector(&quot;.answer4&quot;);
const choices = document.querySelector(&quot;.choices&quot;);
let score = 0;
let Highscore = 0;
const numberForNumberGen = function() {
  return Math.trunc(Math.random() * 12 + 1);
};
const choicesAssinger = function(usersChoice) {
  // document.getElementById(correct).innerHTML = questionGen();
  console.log(`user choice ${usersChoice}`);
  const answerText = questionGen();
  const correct = numberGen(4);
  console.log(`correct choice ${correct}`);
  if (correct === 1) {
    answer1.innerHTML = answerText;
    answer2.innerHTML = answerText + numberForNumberGen();
    answer3.innerHTML = answerText - numberForNumberGen();
    answer4.innerHTML =
      answerText + numberForNumberGen() - numberForNumberGen();
  } else if (correct === 2) {
    answer2.innerHTML = answerText;
    answer1.innerHTML = answerText - numberForNumberGen();
    answer4.innerHTML = answerText - numberForNumberGen();
    answer3.innerHTML =
      answerText + numberForNumberGen() - numberForNumberGen();
  } else if (correct === 3) {
    answer3.innerHTML = answerText;
    answer4.innerHTML = answerText + numberForNumberGen();
    answer2.innerHTML = answerText - numberForNumberGen();
    answer1.innerHTML =
      answerText + numberForNumberGen() - numberForNumberGen();
  } else if (correct === 4) {
    answer4.innerHTML = answerText;
    answer3.innerHTML = answerText + numberForNumberGen();
    answer1.innerHTML = answerText - numberForNumberGen();
    answer2.innerHTML =
      answerText + numberForNumberGen() - numberForNumberGen();
  }
  // return correct;
  console.error(correct);
  console.error(usersChoice);

  console.log(correct == usersChoice);
  if (correct == usersChoice) {
    console.log(&quot;correct&quot;);
    document.querySelector(&quot;body&quot;).style.background = &quot;green&quot;;
    score++;
    questionGen();
    choicesAssinger();
    Navscore.innerHTML = score;
    if (score &gt; Highscore) {
      Highscore = score;
      highScoreNumber.innerHTML = Highscore;
    }
  } else {
    if (score !== 0) {
      document.querySelector(&quot;body&quot;).style.background = &quot; #925e36&quot;;
      Navscore.innerHTML = &quot;Please click Reset&quot;;
      choices1.removeEventListener(&quot;click&quot;, handler);
      choices2.removeEventListener(&quot;click&quot;, handler);
      choices3.removeEventListener(&quot;click&quot;, handler);
      choices4.removeEventListener(&quot;click&quot;, handler);
    }
  }
  // return rightChoiceNumber;
};
const start = () =&gt; {
  // choicesAssinger();
  choices1.addEventListener(&quot;click&quot;, handler);
  choices2.addEventListener(&quot;click&quot;, handler);
  choices3.addEventListener(&quot;click&quot;, handler);
  choices4.addEventListener(&quot;click&quot;, handler);
};
const numberGen = function(n) {
  const number = Math.trunc(Math.random() * n + 1);

  return number;
};

const questionGen = function() {
  const num1 = numberGen(numberForNumberGen());
  const num2 = numberGen(numberForNumberGen());
  const answer = num1 * num2;
  console.log(answer);
  const questionWriting = `${num1} x ${num2}`;
  question.innerHTML = questionWriting;
  return answer;
};

function handler(event) {
  const usersChoice = event.target.id;

  choicesAssinger(usersChoice);
}

resetBtn.addEventListener(&quot;click&quot;, () =&gt; {
  start();
  document.querySelector(&quot;body&quot;).style.background = &quot; #925e36&quot;;
  score = 0;
  Navscore.innerHTML = 0;
  questionGen();
});
questionGen();
// choicesAssinger();
start();

<!-- language: lang-html -->

&lt;nav&gt;
  &lt;div class=&quot;reset utilites&quot;&gt;Reset&lt;/div&gt;
  &lt;div class=&quot;score utilites&quot;&gt;
    Score: &lt;span class=&quot;ScoreNumber&quot;&gt; 0&lt;/span&gt;
  &lt;/div&gt;
  &lt;div class=&quot;highScore utilites&quot;&gt;
    High Score: &lt;span class=&quot;highScoreNumber&quot;&gt; 0&lt;/span&gt;
  &lt;/div&gt;
&lt;/nav&gt;
&lt;section&gt;
  &lt;div class=&quot;choices&quot; id=&quot;1&quot;&gt;
    &#128682;
    &lt;div class=&quot;answer answer1&quot;&gt;answer&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;choices&quot; id=&quot;2&quot;&gt;
    &#128682;
    &lt;div class=&quot;answer answer2&quot;&gt;answer&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;choices&quot; id=&quot;3&quot;&gt;
    &#128682;
    &lt;div class=&quot;answer answer3&quot;&gt;answer&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;choices&quot; id=&quot;4&quot;&gt;
    &#128682;
    &lt;div class=&quot;answer answer4&quot;&gt;answer&lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;
&lt;div class=&quot;question&quot;&gt;---&lt;/div&gt;

<!-- end snippet -->

答案1

得分: 1

我发现了提供的代码中的特定问题,并且看到当我回答正确时,我的分数确实变成了1。但是,当回答正确时,HTML body的背景变为棕色(十六进制:#925e36),而我认为你的意图是将其变为绿色。

事实上,body确实会变成绿色,但它会迅速(对于肉眼来说几乎是不可察觉的,因为速度很快)变成棕色。这是因为在设置body为绿色的同一代码块内,你调用了choicesAssinger();而没有提供参数。这会重置选项,并且因为没有参数,将usersChoice设置为undefined,这意味着用户永远不会有正确的选项,所以body会变成棕色,因为score !== 0

我不确定是否有一种小的更改可以修复你的逻辑。总的来说,我发现代码非常难以阅读和理解,因为它们都非常紧密地相互关联。

我真的很想帮助你简化这个解决方案,但我认为如果不进行重写,我无法这样做。

我会采取以下方法:

  • 封装状态(变化的值)到一个单一的对象中。
  • 创建一个单一的render函数,根据状态对象渲染HTML。
  • 创建事件处理程序,其工作是根据用户的操作更新状态,然后调用render函数。

遵循这些指南,我重新编写了你的代码。我可能无法解释我想要解释的所有内容,但我会尽力在注释中解释我的决策:

// 用于洗牌选项的实用函数
// 复制自:https://stackoverflow.com/a/33760558/3397771
function shuffle(array) {
  let currentIndex = array.length, randomIndex;

  // 在还有要洗牌的元素时进行洗牌。
  while (currentIndex != 0) {

    // 选择一个剩余的元素。
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex--;

    // 并与当前元素交换位置。
    [array[currentIndex], array[randomIndex]] = [
      array[randomIndex], array[currentIndex]];
  }

  return array;
}

// 与原始帖子中相同的数字生成器,只是改名了
const generateNumber = function() {
  return Math.trunc(Math.random() * 12 + 1);
};

// 生成新选项集的函数
// 确保正确选项包含在内
// 还确保没有重复选项
const generateOptions = (state) => {
  const product = state.numbersToMultiply[0] * state.numbersToMultiply[1];
  const options = (new Array(state.numOptions - 1).fill(null)).reduce((acc) => {
      let nextTry = Math.round(Math.random() * 100);

      // 确保选项中没有重复的选项
      while (acc.includes(nextTry)) {
        nextTry = Math.round(Math.random() * 100);
      }

      acc.push(nextTry);

      return acc;
    }, [product]); // 以正确答案开始

    return shuffle(options);
}

// 状态对象包含了所有在应用程序生命周期内变化的值
// 可以说`numOptions`可能放在配置中,因为它不会变化
const state = {
  highScore: 0,
  isShowOptions: false,
  numbersToMultiply: [generateNumber(), generateNumber()],
  numOptions: 4,
  options: [],
  selectedOption: null,
  score: 0
};

// 设置第一个问题的选项
state.options = generateOptions(state);

// 我们将与之交互或设置内容的DOM元素
const choices = document.getElementById("Choices");
const highScore = document.getElementById("HighScore");
const next = document.getElementById("Next");
const question = document.getElementById("Question");
const reset = document.getElementById("Reset");
const score = document.getElementById('Score');

// 单一的渲染函数
// 它将从状态对象中获取所有所需的值
const render = (state) => {
  const product = state.numbersToMultiply[0] * state.numbersToMultiply[1];
  const optionElements = state.options.map(option => {
    let className = '';

    // 确定此选项的类
    // 这些类的定义必须在CSS中定义
    if (state.isShowOptions) {
      if (state.selectedOption === option && state.selectedOption === product) {
        className = 'correct';
      } else if (state.selectedOption === option) {
        className = 'incorrect';
      } else if (product === option) {
        className = 'actual';
      }
    }

    // 将选项映射到要插入到DOM中的<div>元素
    return `<div class="${className}" data-option="${option}">🚂 ${state.isShowOptions ? option : ''}</div>`;
  });

  choices.innerHTML = optionElements.join('');
  highScore.textContent = String(state.highScore);
  question.innerHTML = `${state.numbersToMultiply[0]} x ${state.numbersToMultiply[1]}`;
  score.textContent = String(state.score);
};

choices.addEventListener('click', (event) => {
  // 如果我们正在显示选项,
  // 当点击选项时,我们不希望状态改变
  // 所以我们提前返回
  if (state.isShowOptions) { return; }

  const selectedOption = Number(event.target.dataset.option);
  const correctOption = state.numbersToMultiply[0] * state.numbersToMultiply[1];
  const isCorrect = correctOption === selectedOption;

  state.isShowOptions = true;
  state.selectedOption = selectedOption;
  state.score += isCorrect ? 1 : 0;
  state.highScore = Math.max(state.score, state.highScore);

  render(state);
});

next.addEventListener('click', () => {
  state.isShowOptions = false;
  state.numbersToMultiply = [generateNumber(), generateNumber()];
  state.options = generateOptions(state);

  render(state);
});

reset.addEventListener('click', () => {
  state.highScore = state.score;
  state.isShowOptions = false;
  state.numbersToMultiply = [generateNumber(), generateNumber()];
  state.options = generateOptions(state);
  state.score = 

<details>
<summary>英文:</summary>

I was having difficulty understanding what the specific issue is with the code you provided because I _did_ see my score change to 1 when I got a correct answer. However, upon getting a correct answer, the background of the HTML body turned to brown (hex: #925e36) whereas I think you intend for it to turn green.

The truth is, the body actually does turn green, but it quickly (imperceptibly to the eye because it is so fast) turns brown. This is because within the same code block that sets the body to green, you are calling `choicesAssinger();` with no argument. This resets the options and, because there is no argument, sets the `usersChoice` to `undefined` - meaning the user will never have the correct option and so the body will switch to brown because `score !== 0`.

I am not sure that there is a small change that can correct your logic. Overall, I find the code very hard to read and reason about because it is all so deeply connected (coupled).

I really want to help you to simplify this solution, but I don&#39;t think I can do so without significantly re-writing the code.

I would approach this by:
* Encapsulating the state (the values that change) into a single object.
* Having a single `render` function that will render the HTML according to the state object.
* Have event handlers whose job is to update the state according to the user&#39;s action and then call the `render` function.

Following these guides, I have re-written your code. I don&#39;t think I will be able to explain everything I would like to, but I will try my best to explain my decisions in comments:

```js
// utility function to shuffle the options
// copied from: https://stackoverflow.com/a/33760558/3397771
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;
}

// same number generator as in original post, just renamed
const generateNumber = function() {
  return Math.trunc(Math.random() * 12 + 1);
};

// function to generate a new set of options
// it ensures that the correct option is in the set
// it also ensure no duplicate options
const generateOptions = (state) =&gt; {
	const product = state.numbersToMultiply[0] * state.numbersToMultiply[1];
  const options = (new Array(state.numOptions - 1).fill(null)).reduce((acc) =&gt; {
      let nextTry = Math.round(Math.random() * 100);

      // ensure no duplicates in options
      while (acc.includes(nextTry)) {
        nextTry = Math.round(Math.random() * 100);
      }

      acc.push(nextTry);

      return acc;
    }, [product]); // start with the correct answer

    return shuffle(options);
}

// state object contains all of the values that change
// over the life of the app
// arguably `numOptions` could go in a config since it does not change
const state = {
  highScore: 0,
  isShowOptions: false,
  numbersToMultiply: [generateNumber(), generateNumber()],
  numOptions: 4,
  options: [],
  selectedOption: null,
  score: 0
};

// set the options for the first question
state.options = generateOptions(state);

// DOM elements that we will interact with or set the contents of
const choices = document.getElementById(&quot;Choices&quot;);
const highScore = document.getElementById(&quot;HighScore&quot;);
const next = document.getElementById(&quot;Next&quot;);
const question = document.getElementById(&quot;Question&quot;);
const reset = document.getElementById(&quot;Reset&quot;);
const score = document.getElementById(&#39;Score&#39;);

// single render function
// it will get all of the values it needs from the state object
const render = (state) =&gt; {
  const product = state.numbersToMultiply[0] * state.numbersToMultiply[1];
  const optionElements = state.options.map(option =&gt; {
  	let className = &#39;&#39;;
    
    // determine the class for this option
    // the definition for these classes must be defined in CSS
    if (state.isShowOptions) {
      if (state.selectedOption === option &amp;&amp; state.selectedOption === product) {
      	className = &#39;correct&#39;;
      } else if (state.selectedOption === option) {
      	className = &#39;incorrect&#39;;
      } else if (product === option) {
      	className = &#39;actual&#39;;
      }
    }
    
    // map options to &lt;div&gt; elements to be injected into DOM
    return `&lt;div class=&quot;${className}&quot; data-option=&quot;${option}&quot;&gt;&#128682; ${state.isShowOptions ? option : &#39;&#39;}&lt;/div&gt;`;
  });

  choices.innerHTML = optionElements.join(&#39;&#39;);
  highScore.textContent = String(state.highScore);
  question.innerHTML = `${state.numbersToMultiply[0]} x ${state.numbersToMultiply[1]}`;
  score.textContent = String(state.score);
};

choices.addEventListener(&#39;click&#39;, (event) =&gt; {
  // if we are showing the options,
  // we don&#39;t want the state to change when options are clicked
  // so we return early
  if (state.isShowOptions) { return; }

  const selectedOption = Number(event.target.dataset.option);
  const correctOption = state.numbersToMultiply[0] * state.numbersToMultiply[1];
  const isCorrect = correctOption === selectedOption;

  state.isShowOptions = true;
  state.selectedOption = selectedOption;
  state.score += isCorrect ? 1 : 0;
  state.highScore = Math.max(state.score, state.highScore);
  
  render(state);
});

next.addEventListener(&#39;click&#39;, () =&gt; {
  state.isShowOptions = false;
  state.numbersToMultiply = [generateNumber(), generateNumber()];
  state.options = generateOptions(state);
  
  render(state);
});

reset.addEventListener(&#39;click&#39;, () =&gt; {
  state.highScore = state.score;
  state.isShowOptions = false;
  state.numbersToMultiply = [generateNumber(), generateNumber()];
  state.options = generateOptions(state);
  state.score = 0;
  
  render(state);
})

// on app start, render the first question
render(state);

I have created a fiddle for reference.

huangapple
  • 本文由 发表于 2023年2月6日 02:14:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75354466.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定