LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-02-2021, 11:23 PM   #1
gacl
Member
 
Registered: Feb 2004
Posts: 64

Rep: Reputation: 23
Question game skips questions the second time around


Hello,

This is from the book Javascript: Novice To Ninja. The game works correctly the first time around (3 questions) but will skip questions in subsequent games. I think it has something to do with the event listener or maybe "this". I've tried enough times to solve this... Here's the code:

HTML:
Code:
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<meta name="description" content="A quiz game for ninjas" />
		<meta name="author" content="gacl" />
		<title>
			Quiz Ninja
		</title>
		<link rel="stylesheet" href="css/styles.css" />
	</head>
	<body>
		<header>
			<h1>
				Quiz Ninja!
			</h1>
			<p>
				Score: <strong id="score">0</strong>
			</p>
			<p id="timer"></p>
		</header>
		<section id="question"></section>
		<form id="answer">
		</form>
		<section id="feedback"></section>
		<button id="start">
			Click to play Quiz Ninja!
		</button>
		<script src="js/scripts.js"></script>
	</body>
</html>
JS:
Code:
(function () {
	"use strict";

	// DOM references
	var $question = document.getElementById('question');
	var $score = document.getElementById('score');
	var $feedback = document.getElementById('feedback');
	var $start = document.getElementById('start');
	var $form = document.getElementById('answer');
	var $timer = document.getElementById('timer');

	// View functions
	function update(element,content,klass) {
		var p = element.firstChild || document.createElement('p');
		p.textContent = content;
		element.appendChild(p);
		if (klass) {
			p.className = klass;
		}
	}

	// Event listeners
	$start.addEventListener('click',function() {
			new Game(quiz);
		},false);

	var quiz = {
		"name": "Super Hero Name Quiz",
		"description": "How many super heroes can you name?",
		"question": "What is the real name of ",
		"questions": [
			{"question": "Superman", "answer": "Clarke Kent", "asked": "false"},
			{"question": "Wonder Woman", "answer": "Dianna Prince", "asked": "false"},
			{"question": "Batman", "answer": "Bruce Wayne", "asked": "false"}
		]
	};

	function hide(element) {
		element.style.display = 'none';
	}

	function show(element) {
		element.style.display = 'block';
	}

	// Hide the form at the start of the game
	hide($form);

	var score = 0; // Initialize score

	function random(a,b,callback) {
		if (b === undefined) {
			// If only one argument is supplied, assume the lower limit is 1
			b = a, a = 1;
		}
		var result = Math.floor((b - a + 1) * Math.random()) + a;
		if (typeof callback === 'function') {
			result = callback(result);
		}
		return result;
	}

	// Method definitions
	Game.prototype.chooseQuestion = function() {
		console.log("chooseQuestion() called");
		var questions = this.questions.filter(function(question) {
				return question.asked === "false";
			});
		// Added by gacl
		if (questions == false) {
			return this.gameOver();
		}
		// Set the current question
		this.question = questions[random(questions.length) - 1];
		this.ask(this.question);
	}

	Game.prototype.ask = function(question) {
		console.log("ask() called");
		var quiz = this;
		// Set the question.asked property to true so it's not asked again
		question.asked = true;
		update($question,this.phrase + question.question + "?");
		// Clear the previous options
		$form.innerHTML = "";
		// Create an array to put the different options in and a button variable
		var options = [], button;
		var option1 = chooseOption();
		options.push(option1.answer);
		var option2 = chooseOption();
		options.push(option2.answer);
		// Add the actual answer at a random place in the options array
		options.splice(random(0,2),0,this.question.answer);
		// Loop through each option and display it as a button
		options.forEach(function(name) {
			button = document.createElement("button");
			button.value = name;
			button.textContent = name;
			$form.appendChild(button);
		});

		// Choose and option from all the possible answers but without choosing the answer or the same option twice
		function chooseOption() {
			var option = quiz.questions[random(quiz.questions.length) - 1];
			// Check to see if the option chosen is the current question or already one of the options, if it is then recursively call this function until it isn't
			if (option === question || options.indexOf(option.answer) !== -1) {
				return chooseOption();
			}
			return option;
		}
	}

	Game.prototype.check = function(answer) {
		console.log("check() called");
		if (answer === this.question.answer) {
			update($feedback,"Correct!","right");
			// Increase score by 1
			this.score++;
			update($score,this.score);
		} else {
			update($feedback,"Wrong!","wrong");
		}
		this.chooseQuestion();
	}

	Game.prototype.countDown = function() {
		// This is called every second and decreases the time
		// Decrease time by 1
		this.time--;
		// Update the time displayed
		update($timer,this.time);
		// The game is over if the timer has reached 0
		if (this.time <= 0) {
			this.gameOver();
		}
	}

	Game.prototype.gameOver = function() {
		console.log("gameOver() invoked");
		// Inform the player that the game has finished and tell them how many points they have scored
		update($question,"Game over. You scored " + this.score + " points");
		// Stop the countdown interval
		window.clearInterval(this.interval);
		hide($form);
		show($start);
	}

	function Game(quiz) {
		this.questions = quiz.questions;
		// Added by gacl
		for (let question of this.questions) {
			question.asked = "false";
		}
		this.phrase = quiz.question;
		this.score = 0; // Initialize score
		update($score,this.score);
		// Initialize timer and set up an interval that counts down
		this.time = 20;
		update($timer,this.time);
		this.interval = window.setInterval(this.countDown.bind(this),1000);
		// Hide button and show form
		hide($start);
		show($form);
		// Add event listener to form for when it's submitted
		$form.addEventListener('click', function(event) {
				event.preventDefault();
				this.check(event.target.value);
			}.bind(this),false);
		this.chooseQuestion();
	}
} ())
There's a CSS file but I don't think we need it here. Thanks!
 
Old 01-03-2021, 10:04 PM   #2
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,269
Blog Entries: 24

Rep: Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206
Quote:
Originally Posted by gacl View Post
Hello,
I've tried enough times to solve this... Here's the code:
There is no magic number of tries I am aware of which passes responsibility for debugging your code to others, and you do not say what you consider to be enough times, so we are kind of in the dark here!

It would also be helpful to others willing to offer assistance if you would explain what you have done to try to resolve the problem and what you found out in the process, including any error messages that may have been passed to the debug console.

Please review the Site FAQ for guidance in posting your questions and general forum usage. Especially, read the link in that page, How To Ask Questions The Smart Way. The more effort you put into understanding your problem and framing your questions, the better others can help!
 
2 members found this post helpful.
Old 01-04-2021, 12:41 PM   #3
scasey
LQ Veteran
 
Registered: Feb 2013
Location: Tucson, AZ, USA
Distribution: CentOS 7.9.2009
Posts: 5,748

Rep: Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222Reputation: 2222
The JavaScript only has three questions. It also contains code to use each question only once.
So, once they have all been displayed, there are no more questions to ask.
It’s doing what it’s coded to do. (As programs always do)
Note that I made the above determinations by only reading the comments...not by analyzing the code. It is, of course, possible that the code doesn’t do what the comments say. Been there, done that.

If you want to play it again, you’ll need to reload the web page, or add code to reset the use each question once flags. The latter would be a good learning experience.

Does your book not offer suggestions for debugging code? I like to use alert() to output variables I want to inspect, but they can also be output to the web page.
Does you browser offer a debugging console? The current Firefox does.

That said, I second what astrogeek posted. As you’re doing this to learn, you need to tell what you’ve tried and what result you got.
 
Old 01-04-2021, 05:10 PM   #4
dugan
LQ Guru
 
Registered: Nov 2003
Location: Canada
Distribution: distro hopper
Posts: 11,249

Rep: Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323Reputation: 5323
If the code is taken directly from the book, then you should be aware that it's both outdated and bad.

For example, it has "var" statements in the middle of code blocks. These should always be at the beginning, because the interpreter actually moves them up there. If you want to declare variables mid-block, then you use "let", which isn't subjected to hoisting.
 
Old 01-09-2021, 11:11 PM   #5
gacl
Member
 
Registered: Feb 2004
Posts: 64

Original Poster
Rep: Reputation: 23
Sorry, I did try to debug it with the console (Chromium). No errors. The steps to reproduce the issue are:

1. Click on the button "Click to play Quiz Ninja"
2. Answer question 1
3. Answer question 2
4. Answer question 3
5. Do not reload the page. Instead click on the button "Click to play Quiz Ninja"
6. Attempt to answer all three questions again (It's supposed to ask the same three questions). You will not succeed because the game will only ask you two questions before going to "Game over".
7. If you keep playing (without reloading) it will ask only one question from then on.

At this point when I use the debugger I can see that after the first question is asked it goes back to the event listener but does not wait for user input. Instead it keeps going through the question/answer cycle by itself. I think that this is the problem, that the event listener for the form stops listening. What could cause it to stop listening?
 
Old 02-18-2021, 05:54 AM   #6
Geist
Member
 
Registered: Jul 2013
Distribution: Slackware 14 / current
Posts: 442

Rep: Reputation: 196Reputation: 196
Make sure to reset the game state to the initial, clean slate properly at the end of the game.
I'm not too knowledgable with javascript, but maybe the fault is somewhere where "questions" was used with "this." and without "this."
Aka, some sort of scope error which is valid code (aka not a syntax error or anything), but just a messup by the programmer.

Edit:
By the way, this program seems kinda awful all around.

Last edited by Geist; 02-18-2021 at 07:45 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
amarok skips every second song theacerguy Linux - Software 0 06-16-2009 10:11 AM
[SOLVED] Audio skips when scrolling, skips horribly when watching video with Compiz enabled Kiboney Linux - Newbie 16 06-02-2009 10:19 PM
Second time around pablano LinuxQuestions.org Member Intro 4 09-10-2007 09:05 AM
Loving it the second time around SactoBob LinuxQuestions.org Member Intro 3 01-04-2007 01:57 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:44 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration