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
"use strict";
const resetBtn = document.querySelector(".reset");
const Navscore = document.querySelector(".ScoreNumber");
const scoreToReset = document.querySelector(".score");
const question = document.querySelector(".question");
const highScoreNumber = document.querySelector(".highScoreNumber");
const choices1 = document.getElementById("1");
const choices2 = document.getElementById("2");
const choices3 = document.getElementById("3");
const choices4 = document.getElementById("4");
const answer1 = document.querySelector(".answer1");
const answer2 = document.querySelector(".answer2");
const answer3 = document.querySelector(".answer3");
const answer4 = document.querySelector(".answer4");
const choices = document.querySelector(".choices");
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("correct");
document.querySelector("body").style.background = "green";
score++;
questionGen();
choicesAssinger();
Navscore.innerHTML = score;
if (score > Highscore) {
Highscore = score;
highScoreNumber.innerHTML = Highscore;
}
} else {
if (score !== 0) {
document.querySelector("body").style.background = " #925e36";
Navscore.innerHTML = "Please click Reset";
choices1.removeEventListener("click", handler);
choices2.removeEventListener("click", handler);
choices3.removeEventListener("click", handler);
choices4.removeEventListener("click", handler);
}
}
// return rightChoiceNumber;
};
const start = () => {
// choicesAssinger();
choices1.addEventListener("click", handler);
choices2.addEventListener("click", handler);
choices3.addEventListener("click", handler);
choices4.addEventListener("click", 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("click", () => {
start();
document.querySelector("body").style.background = " #925e36";
score = 0;
Navscore.innerHTML = 0;
questionGen();
});
questionGen();
// choicesAssinger();
start();
<nav>
<div class="reset utilites">Reset</div>
<div class="score utilites">
Score: <span class="ScoreNumber"> 0</span>
</div>
<div class="highScore utilites">
High Score: <span class="highScoreNumber"> 0</span>
</div>
</nav>
<section>
<div class="choices" id="1">
🚪
<div class="answer answer1">answer</div>
</div>
<div class="choices" id="2">
🚪
<div class="answer answer2">answer</div>
</div>
<div class="choices" id="3">
🚪
<div class="answer answer3">answer</div>
</div>
<div class="choices" id="4">
🚪
<div class="answer answer4">answer</div>
</div>
</section>
<div class="question">---</div>
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't think I can do so without significantly re-writing the code.
I would approach this by:
render
function that will render the HTML according to the state object.render
function.Following these guides, I have re-written your code. I don'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:
// 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) => {
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);
// 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("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');
// single render function
// it will get all of the values it needs from the state object
const render = (state) => {
const product = state.numbersToMultiply[0] * state.numbersToMultiply[1];
const optionElements = state.options.map(option => {
let className = '';
// determine the class for this option
// the definition for these classes must be defined in 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';
}
}
// map options to <div> elements to be injected into DOM
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 we are showing the options,
// we don'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('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 = 0;
render(state);
})
// on app start, render the first question
render(state);
I have created a fiddle for reference.