See below for a re-worked version of the code for your consideration. I would suggest that this version has been structured in a clearer manner.
There is also the following added functionality:
- Start button so that the quiz doesn't begin immediately on page load
- Recognition in written feedback of questions that are essentially skipped by pressing the 'escape' key or submitting a blank answer during the prompt
Preview
<!doctype html>
<html>
<head>
<title>Math.floor</title>
<style>
#quiz-feedback {
float: left;
width: 400px;
min-height: 180px;
padding: 20px;
border: 2px solid #efefef;
}
</style>
<script>
var scorecard = {
correct: 0,
incorrect: 0,
feedback: []
};
var quiz = [];
function initialize() {
var chosenTopics = ['-', '+', '*', '/'];
// Generate quiz questions
for(var i = 0; i < chosenTopics.length; i++) {
quiz.push(createQuestion(chosenTopics[i]));
}
startGame(quiz);
}
function createQuestion(operator) {
var x = Math.floor(Math.random() * 11);
var y = Math.floor(Math.random() * 11);
var answer;
switch(operator) {
case '+': {
answer = x + y;
break;
}
case '-': {
answer = x - y;
break;
}
case '*': {
answer = x * y;
break;
}
case '/': {
answer = x / y;
break;
}
}
var question = x + ' ' + operator + ' ' + y;
return {
questionText: 'What is ' + question + '?',
question: question,
answer: answer.toString()
}
}
function startGame(quiz) {
resetGame();
for(var i = 0; i < quiz.length; i++) {
var userAnswer = prompt(quiz[i].questionText);
var feedback = quiz[i].question;
if(userAnswer === quiz[i].answer) {
// Answered correctly
scorecard.correct++;
feedback = feedback + ' = ' + userAnswer + ' is correct';
} else if(userAnswer === null || userAnswer === '') {
// Not answered
scorecard.incorrect++;
feedback = feedback + ' was skipped. The correct answer is ' + quiz[i].answer;
} else {
// Answered incorrectly
scorecard.incorrect++;
feedback = feedback + ' = ' + userAnswer + ' is INCORRECT. The correct answer is ' + quiz[i].answer;
}
scorecard.feedback.push(feedback);
updateFeedbackDisplay();
}
var verdict = 'You have answered ' + scorecard.correct + ' questions out of ' + quiz.length + ' correctly.';
scorecard.feedback.push(verdict);
updateFeedbackDisplay();
}
function updateFeedbackDisplay() {
var feedbackBox = document.getElementById('quiz-feedback');
var outputHTML = '';
for(var i = 0; i < scorecard.feedback.length; i++) {
outputHTML = outputHTML + '<p>' + scorecard.feedback[i] + '</p>';
}
feedbackBox.innerHTML = outputHTML;
}
function resetGame() {
quiz = [];
scorecard.correct = 0;
scorecard.incorrect = 0;
scorecard.feedback = [];
var feedbackBox = document.getElementById('quiz-feedback');
feedbackBox.innerHTML = '';
}
</script>
</head>
<body>
<h1> Math.floor: The Maths Game</h1>
<p><a href="#" onclick="initialize();">Start Quiz</a></p>
<div id="quiz-feedback"</div>
</body>
</html>
Reasons why:
Primarily the code has been separated out into more clearly-named functions, each responsible for a separate contribution to the workings of the app, e.g. createQuestion(), resetGame(), etc.
This is instead of code that is related to for example both updating the score and rendering the next question on the screen in the same function, as is the case with the original code in the function interact() (now found separately in startGame() and updateFeedbackDisplay()).
If you want to either change the scoring system, change the format of the questions, or change how the game is presented, it's much easier to manage if the code for these separated aspects are not mingled together. They are now separate. It also means that changes are less error prone, with this approach you are much more likely to be able to change one function without affecting the rest of the app, unlike before. In other words, the code is a bit more modular/loosely-coupled between functions and therefore easier to scale (two very important principles of good development).
Other reasons why:
In specifying the type of questions the developer wants, if there's a 1-to-1 mapping between a number and the maths operator as seen in the original code, then the number is irrelevant and it would be clearer to use the operator directly:
- Before: questions(1); questions(4); ...
- After: var chosenTopics = ['-', '+', '*', '/']; // Add as many operator string values to this array as desired
The document.write method, commented upon by other users, has now been withdrawn. Instead the feedback messages are gathered inside an array (scorecard.feedback) and after each question the contents of this array is cycled through, pieced together, and set as the HTML of the div element "quiz-feedback" (see updateFeedbackDisplay() function)
The above version implements the switch statement suggestion from Snowbody
- The above version uses more meaningful variable names as pointed out by RoToRa
Apologies for not including my reasoning originally, hope this helps.