How to fix clearInterval() not stopping the interval? - javascript

I made an interval connected to a button that only runs when you have a certain amount of money and lemonade. Then I created an if statement that makes it so that when you run out of lemonade, then the interval stops. I used clearInterval() and for some reason the interval doesn't stop, and the number of lemonade goes into the negatives. Obviously you can't have a negative amount of something!
I've looked at all of the other questions with similar problems to me, but they didn't really answer my question. They all have different variables and it was hard to find an answer pertaining to my code.
Here's my code:
let autoBtnTwo = document.getElementById("autoBtnTwo");
let lemonade = 0;
let btnTwo = document.getElementById("btnTwo")
function btnTwoCost() {
wallet.removeCash(20);
update();
document.getElementById("lemonade").innerHTML = lemonade += 30
}
function double() {
if (wallet.getCash() >= 50) {
wallet.addCash(2)
update();
document.getElementById("lemonade").innerHTML = lemonade -= 1;
}
}
function autoLemonade() {
if (wallet.getCash() >= 3000) {
wallet.removeCash(3000);
var myint = setInterval(double, 1000);
autoBtnTwo.disabled = false;
update();
}
if (wallet.getCash() <= 2999) {
autoBtnTwo.disabled = true;
}
if (lemonade <= 0) {
autoBtnTwo.disabled = true;
btnTwo.disabled = true;
}
}
function stopInterval() {
var myint = setInterval(double, 1000);
if (lemonade <= 0) {
clearInterval(myint);
stopInterval();
}
}
function thousand() {
wallet.addCash(1000)
update();
if (wallet.getCash() >= 3000) {
autoBtnTwo.disabled = false;
}
}
function Wallet() {
return {
addCash: function(val) {
number += val;
},
getCash: function() {
return number;
},
removeCash: function(val) {
number -= val;
}
}
}
var number = 0;
const wallet = new Wallet();
var SUFFIXES = 'KMBTqQsSOND';
function update() {
document.getElementById('number').textContent = getSuffixedNumber(wallet.getCash());
}
function getSuffixedNumber(num) {
var power = Math.floor(Math.log10(num));
var index = Math.floor(power / 3)
num = num / Math.pow(10, (index * 3)); // first 3 digits of the number
return num.toFixed(1) + (SUFFIXES[index - 1] || ''); // default to no suffix if it gets an out of bounds index
}
<button onclick="autoLemonade()" class="chocolate-bar-auto" id="autoBtnTwo" disabled>
Hire worker: <br> -$3000<br> Sells Lemonade
</button>
<button onclick="thousand()">to get to $3000 for testing </button>
<button onclick="btnTwoCost()"> buy lemonade -$20</button>
<button onclick="double()">sell lemonade </button>
<div class="cash-div">
Cash: <div id="number">0</div>
</div>
<div class="lemonade-div">
Lemonade: <div id="lemonade">0</div>
</div>
Sorry if this version is glitchy. All of the code I used to prevent the glitches makes the code longer, which it is already long enough. press the $3,000 button 4 times, then the buy lemonade, and then the hire worker button and you will see what happens once it gets to 0.
The interval should stop adding money, and stop reducing the amount of lemonade when lemonade reaches 0, but instead it keeps going into the negatives.

Related

JS random order showing divs delay issue

I got function within JS which is supposed to show random order divs on btn click.
However once the btn is clicked user got to wait for initial 10 seconds ( which is set by: setInterval(showQuotes, 10000) ) for divs to start showing in random order which is not ideal for me.
JS:
var todo = null;
var div_number;
var used_numbers;
function showrandomdivsevery10seconds() {
div_number = 1;
used_numbers = new Array();
if (todo == null) {
todo = setInterval(showQuotes, 10000);
$('#stop-showing-divs').css("display", "block");
}
}
function showQuotes() {
used_numbers.splice(0, used_numbers.length);
$('.container').hide();
for (var inc = 0; inc < div_number; inc++) {
var random = get_random_number();
$('.container:eq(' + random + ')').show();
}
$('.container').delay(9500).fadeOut(2000);
}
function get_random_number() {
var number = randomFromTo(0, 100);
if ($.inArray(number, used_numbers) != -1) {
return get_random_number();
} else {
used_numbers.push(number);
return number;
}
}
function randomFromTo(from, to) {
return Math.floor(Math.random() * (to - from + 1) + from);
}
Question: How to alter the code so upon the btn click divs will start showing right away without initial waiting for 10 seconds? (take in mind I want to keep any further delay of 10 seconds in between of each div being shown)
Thank you.
Call it when you begin the interval
todo = setInterval((showQuotes(),showQuotes), 10000);

Set a 10-second timer for each subject input

I've been making a typing game at school. The time setting does not work.
A time limit of 10 seconds is attached to each subject. When one subject is finished, the time will be reset to 10 seconds again.Please give me some advice.
1,The user sees the subject text, types the same value into the text box, and presses the OK button.
2,When the OK button is pressed, clear the text box and display the next subject.
3,Repeat steps 1 and 2 5 times.
4,When the ok button is pressed the 5th time, the total number of characters from the 1st to the 5th times, in which the subject and the value entered by the user are incorrect, is displayed on the screen.
⚠️If the OK button is not pressed within 10 seconds, it is an error for the number of characters in the subject.
I left some clarifications as code comments
const subject = document.getElementById("subject");
const timer = document.getElementById("timer");
const input = document.getElementById("text");
const questionList = [
{ text: "Hello", pronunciation: "Hello" },
{ text: "World", pronunciation: "World" },
{ text: "HTML", pronunciation: "HTML" },
{ text: "CSS", pronunciation: "CSS" },
{ text: "PHP", pronunciation: "PHP" },
];
var question =
questionList[Math.floor(Math.random() * questionList.length)];
subject.textContent = question["text"];
var TIME = 10;
var index = 0;
var CorrectCount = 0;
var missTypeCount = 0;
var state;
const countdown = setInterval(function () {
if (TIME > 0) {
timer.textContent = "Time limit:" + --TIME;
}
if (TIME === 0) {
finish();
}
}, 1000);
document.addEventListener("keypress", function(e) {
if (e.key === question["pronunciation"].charAt(index) ) {
index++;
if (index == question["pronunciation"].length ) {
// Here is where a full correct word was completely written.
// Normally here is where you want to increment CorrectCount++ and reset TIME = 10
// However this is redundant, because you are performing these actions on check()
// I would advice to either keep this conditional, or the check() function, not both
CorrectCount;
}
} else {
missTypeCount++;
e.preventDefault();
}
});
function check() {
if(input.value === subject.textContent ) {
CorrectCount++;
init();
}
if (CorrectCount >= 5 ) {
finish();
}
}
function init() {
question =
questionList[Math.floor(Math.random() * questionList.length)];
subject.textContent = question["text"];
index = 0;
input.value = '';
input.focus();
// You need to set/reset the time to 10 here
TIME = 10;
}
function finish() {
clearInterval(countdown);
if (missTypeCount >= 0 ){
subject.textContent="Perfect"
}
// these conditionals are not doing what you want them to do.
// I believe you mean missTypeCount >= 1 && missTypeCount <= 3
if (missTypeCount >= 1 || missTypeCount >= 3 ){
subject.textContent="Good"
}
if (missTypeCount >= 4 || missTypeCount >= 8 ){
subject.textContent="Almost"
}
if (missTypeCount >= 9 ){
subject.textContent="Bad"
}
}
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/test.css">
</head>
<body>
<div>
<div class="subject"><h1 id="subject"></h1></div>
<form name="typing" onsubmit="return false;">
<div class="text">
<input id="text" type="text" autocomplete="off" >
</div>
<div class="btn">
<input type="submit" value="ok" onclick="check();" >
</div>
</form>
<div class="timer">
<p id="timer">Time limit :10</p>
</div>
</div>
<script type="text/javascript" src="../js/test.js"></script>
</body>
</html>
You need to reset the TIME in your init function:
function init() {
question =
questionList[Math.floor(Math.random() * questionList.length)];
subject.textContent = question["text"];
index = 0;
TIME = 10;
input.value = '';
input.focus();
}
Otherwise the time will just keep on running.
Here is a fiddle to try it out.
But you have several other issues: When you misspelled and try to correct yourself within the time, you can not do this. The input is blocked. And you should set the cursor inside of your input when you load the page, or only start the timer when somebody starts typing. otherwise it is really hard to do it in time.
Use the php function time() or try something like that
<script>
var myVar;
var timer = document.getElementById("userInput");
var countDownSeconds;
function startTime(){
myVar = setInterval(start, 1000);
document.getElementById("timerr").innerHTML = timer.value;
countDownSeconds = timer.value;
}
function start(){
countDownSeconds--;
document.getElementById("timerr").innerHTML = countDownSeconds;
if (countDownSeconds == -1){
stop();
document.getElementById("timerr").innerHTML = "0";
}
}
function stop(){
clearInterval(myVar);
}
</script>

JS countdown timer - Pause function

Here's a simple countdown timer that counts from 9 down to 0.
The countdown works fine. But what if I want to pause it mid-flow and then restart from where it was paused?
I have tried (see code below) to interrupt the countdown, save the number it was at, and then restart the function from the new number. But the countdown goes haywire, and I can't see why. Any ideas?
PS. I could cut and paste a timer from elsewhere, but I'm doing this for the learning experience. I'm sure there are better ways to code a countdown timer in JS, but it's bugging me that I can't make THIS way work and think I must be missing something obvious.
Many thanks
var currentTimeInt = 10;
var minn = [];
var stop = 0;
// stop
function stopCounter() {
currentTime = document.getElementById('mins').textContent; // grabs the number of minutes at moment of pause.
stop = 1;
}
// restart
function restart() {
stop = 0;
currentTimeInt = parseInt(currentTime, 10); // converts that number into an integer we can use
document.getElementById("mins").innerHTML=currentTimeInt;
newMinutes(); // restarts the newMinutes function with the start time currentTimeInt set to the time the counter stopped at
}
function newMinutes() {
document.getElementById('mins').innerHTML= currentTimeInt; // displays the counter
for (aa = currentTimeInt-1; aa >= 0; aa--) {
minn.push(aa); // builds an array of numbers in descending order
document.getElementById('mins').innerHTML= minn[aa];
for (let bb=1; bb<=currentTimeInt; bb++) {
if (bb<currentTimeInt) {
setTimeout( function timer(){
if (stop == 0) { // checks if "stop!" has been clicked and returns false to stop the function if that is the case
document.getElementById('mins').innerHTML= minn[bb];
console.log(minn[bb]);
}
else {return false;}
}, bb*1000 );
}
}
}
console.log(currentTimeInt + " the end");
}
<span>Minutes: </span><span id= "mins"></span>
<button onclick="newMinutes()">Go!</button>
<button onclick="stopCounter()">Stop!</button>
<button onclick="restart()">Reset!</button>
You may try this as an example:
var timerId;
var counter;
function start() {
console.log('start');
if (!counter) {
reset();
} else {
loop();
}
}
function pause() {
console.log('pause');
if (timerId) {
clearInterval(timerId);
timerId = null;
}
}
function reset() {
console.log('reset');
pause();
counter = 10;
loop();
}
function loop() {
timerId = setInterval(function() {
if (0 >= counter) {
pause();
return;
}
console.log('counter', counter);
counter--;
}, 500);
}
<button onclick='start();'>Start</button>
<button onclick='pause();'>Pause</button>
<button onclick='reset();'>Reset</button>
Here is my little Countdown with START, PAUSE, RESUME, STOP & RESET features:
var jqcd_start_id = 'input#jqcd_start';
var jqcd_time_id = 'input#jqcd_time';
var jqcd_count_id = 'span#jqcd_count';
var jqcd_end_message = 'Time is up!';
var jqcd_countdown = '';
var jqcd_status = 'stopped';
var jqcd_current = '';
function jqcd(action){
if (action == 'start') {
if (jqcd_status == 'stopped') {
jqcd_updtv(jqcd_start_id, 'Pause');
jqcd_status = 'running';
jqcd_current = jqcd_countdown;
jqcd_updtt(jqcd_count_id, jqcd_countdown);
}
else if (jqcd_status == 'running') {
jqcd_updtv(jqcd_start_id, 'Resume');
jqcd_status = 'paused';
}
else if (jqcd_status == 'paused') {
jqcd_updtv(jqcd_start_id, 'Pause');
jqcd_status = 'running';
}
}
else if (action == 'stop') {
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
jqcd_updtt(jqcd_count_id, jqcd_end_message);
}
else if (action == 'reset') {
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
jqcd_updtt(jqcd_count_id, jqcd_countdown);
}
var a = jqcd_current.split(":");
var m = a[0];
var s = (a[1] - 1);
if (s < 0) {
if (parseInt(m) == 0) {
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
jqcd_updtt(jqcd_count_id, jqcd_end_message);
}
else {
m = m - 1;
s = 59;
}
}
if(s >= 0){
setTimeout(function(){
if (jqcd_status == 'running') {
m = (parseInt(m) < 10)? "0" + parseInt(m): m;
s = (parseInt(s) < 10)? "0" + parseInt(s): s;
jqcd_updtt(jqcd_count_id, m + ":" + s);
jqcd_current = m + ":" + s;
jqcd('');
}
}, 1000);
}
}
function jqcd_updtv(selector, value) {
if (selector != '') {
$(selector).val(value);
}
}
function jqcd_updtt(selector, value) {
if (selector != '') {
$(selector).text(value);
}
}
$(document).ready(function() {
jqcd_countdown = $(jqcd_time_id).val();
jqcd_updtt(jqcd_count_id, jqcd_countdown);
$(jqcd_time_id).keyup(function() {
jqcd_countdown = $(jqcd_time_id).val();
jqcd_updtt(jqcd_count_id, jqcd_countdown);
jqcd_updtv(jqcd_start_id, 'Start');
jqcd_status = 'stopped';
});
});
span#jqcd_count {
font-size: 20pt;
font-weight: bold;
}
input#jqcd_start,
input#jqcd_stop,
input#jqcd_reset {
font-size: 12pt;
font-weight: bold;
}
input#jqcd_start,
input#jqcd_stop,
input#jqcd_reset {
width: 100px;
}
span#jqcd_count {
font-family: "Lucida Console", Monaco, "Courier New", Courier, monospace !IMPORTANT;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="jqcd_count">00:30</span><br><br>
<input type="button" id="jqcd_start" value="Start" onClick="jqcd('start')" />
<input type="button" id="jqcd_stop" value="Stop" onClick="jqcd('stop')" />
<input type="button" id="jqcd_reset" value="Reset" onClick="jqcd('reset')" /><br><br>
<input type="text" id="jqcd_time" value="00:10" />
<br><br>
It is pretty simple to customize. The first four variables in the JavaScript code can be adapted to work with your specific HTML.
If you want an action to take place every second, add your lines of code inside of the "jqcd_updtt" function.
The CSS is completely optional, of course.
The Countdown start time is set dynamically by altering the value in the "jqcd_time" field. If, however, you want to set a static value for the Countdown starting point, you can alter the variables inside the "$(document).ready(function() {" function at the end of the JavaScript code.
PS.
This Countdown has no maximum limit for minutes or seconds
What about keeping it KISS!
let i = 9,j
function chrono(){
if (i>=0){
now.innerText = i--
}
}
<h1><div id="now">⏰ Ready!</div>
<button onclick="setInterval(function(){ chrono() }, 1000);this.style.display='none'">Start</button>
<button onclick="i=10">Reset</button>
<button onclick="j=i;i=-1">Pause</button>
<button onclick="i=j">Continue</button>
This is the most basic example ready to be expanded, mostly there is no clearInterval.
The KISS principle states that most systems work best if they are kept
simple rather than made complicated; therefore simplicity should be a
key goal in design and unnecessary complexity should be avoided.
https://en.wikipedia.org/wiki/KISS_principle
Therefore, js incrementation and setInterval seems easy but they hide complex things.
An other approach using date.now() that provide an accurate unix timestamp based on the system clock, and the web audio api for beeping.
i = Date.now();j=i+10000;z.innerText="Target #"+j
function d(){
if(now.innerText < j){
now.innerText = Date.now()
k(3,603,80)
}
if(now.innerText > j){
now.innerHTML = "<b>TIME TRAVEL COMPLETE!</b>"
k(8,728,100)
}
}
setInterval(function(){ d() }, 100)
a=new AudioContext()
function k(w,x,y){
v=a.createOscillator()
u=a.createGain()
v.connect(u)
v.frequency.value=x
v.type="square"
u.connect(a.destination)
u.gain.value=w*0.01
v.start(a.currentTime)
v.stop(a.currentTime+y*0.001)
}
EPOCH: <out id="now"></out><h6 id="z">
The first issue here is that currentTime isn't globally defined, so it can't be accessed from within restart. Just put var currentTime; at the start of your file.
But you have another serious breaking issue in that you're using setTimeout in a really awkward way. You're creating multiple timeouts all at once and giving them a delay based on their relation tocurrentTimeInt. This has two problems. For one the use of two for loops isn't very efficient and also seems redundant as your inner for loop is just going to count up to the currentTimeInt anyway.
Secondly, you never clear (and probably won't be able to clear) the timeouts. That means when you restart your timer after pausing if any timeouts hadn't yet been fired, then your program will run those and make the minutes jump back and forth between the old timeouts and the new ones you create after unpausing.
I know in your comment you said you wanted to get this to work because you basically did the whole thing yourself, but it may not be worth continuing down this road. After looking at it some I think fixing your program would require it to be restructured, or else require it to be hacked in a way that makes it pretty inefficient. And if you're someone who's just learning Javascript, it's probably better to just start over and do it the right way anyway.
Below is an example of a better way using setInterval rather than setTimeout, but feel free to just try and figure it out on your own.
(There are ways you can improve the functionality of the code below, but it should be enough to get you the general idea)
var startTimeInt = 10;
var currentTimeInt = startTimeInt;
var interval = undefined;
// start the timer
function startCounter() {
if(!interval){
document.getElementById('mins').innerHTML = currentTimeInt;
interval = setInterval(newNumber, 1000) // set an interval
}
}
// stop
function stopCounter() {
// clear the interval
clearInterval(interval)
interval = undefined;
}
// reset the timer
function resetCounter(){
currentTimeInt = startTimeInt;
document.getElementById('mins').innerHTML = currentTimeInt;
//stopCounter(); startCounter();
}
// change the time and handle end of time event
function newNumber(){
currentTimeInt--; // decrement the current time
document.getElementById('mins').innerHTML = currentTimeInt;
if(currentTimeInt == 0){
console.log("Done");
stopCounter();
}
}
<span>Minutes: </span><span id= "mins"></span>
<button onclick="startCounter()">Go!</button>
<button onclick="stopCounter()">Stop!</button>
<button onclick="resetCounter()">Reset!</button>
Here is a working Snippet..
var paused = false;
var started = false;
var stopped = true;
var currentCount = 0;
var running = false;
interval = 1000;
maxCount = 10;
function start() {
if (stopped){
started = true;
paused= false;
stopped = false;
currentCount = maxCount;
loop(); running = true;
return;
}
paused= false;
}
function pause() {
paused= true;
}
function stop(){
paused = false;
started = false;
stopped = true;
running = false;
currentCount = 0;
}
function update(item){
document.getElementById("status").innerHTML = item;
//console.log(item);
--currentCount;
if(currentCount < 0){stop()}
}
function reset() {
currentCount = maxCount;
document.getElementById("status").innerHTML = currentCount;
}
function loop(){
if (!stopped){
if (!paused){update(currentCount);}
setTimeout(function(){loop()}, interval)
}
}
<button onclick='start();'>Start</button>
<button onclick='pause();'>Pause</button>
<button onclick='reset();'>Reset</button>
<button onclick='stop();'>Stop</button>
<div id="status"></div>
for anyone who want to re-use the code, simply change the value of timer and the render function to fit your project
var timer= 10;
var intervalID
// pause/stop
function stopTimer() {
clearInterval(intervalID);
intervalID= null;
}
// restart
function restart() {
stopTimer();
timer= 10;
render();
// Go(); //Optional
}
// start/resume
function Go() {
if(intervalID){
//if interval already created previously, exit function
return
}
intervalID = setInterval(
() => {
if(timer< 1){
//escape from interval so that counter dont go below 0
return stopTimer();
}
timer--;
render();
}, 1000); //1000 milisecond == 1 second
}
function render(){
// it is ok to run render redundantly as it does not mutate the data
// feel free to change this to fit your needs
console.log(timer);
document.getElementById("mins").innerHTML=timer;
}
render() //render once on load
<span>Minutes: </span><span id= "mins"></span>
<button onclick="Go()">Go!</button>
<button onclick="stopTimer()">Stop!</button>
<button onclick="restart()">Reset!</button>

How to change the speed of setInterval in real time

I would like to know how to change the speed of setInterval in real time e.g:
if (score < 10)
repeater = setInterval(function() {
spawnEnemy();
}, 1000);
if (score => 10)
repeater = setInterval(function() {
spawnEnemy();
}, 500);
I know this method doesn't work, but is there a way that I can achieve this some other way?
jsFiddle Demo
There is no way to change the interval speed itself once running. The only way to do it is to have a variable for the speed, and then clear the interval and start a new one with the new speed.
var speed = 500;
var changeSpeed = speed;
repeater = setInterval(repeaterFn, speed);
function repeaterFn(){
spawnEnemy();
if( changeSpeed != speed ){
clearInterval(repeater);
speed = changeSpeed;
repeater = setInterval(repeaterFn, speed);
}
}
function changeRepeater(){
changeSpeed = 700;
}
Another way would be to just use setTimeout rather than setInterval. Do the check every time so you can keep your speed logic in a seperate function.
var game_over = false;
var score = 0;
function getSpeedFromScore(score)
{
if (score > 20) {
game_over = true;
}
if (score < 10) {
return 1000;
} else {
return 500;
}
}
function spawnEnemyThenWait() {
if (!game_over) {
spawnEnemy();
var speed = getSpeedFromScore(score);
setTimeout(spawnEnemyThenWait, speed);
}
}
JS Fiddle http://jsfiddle.net/bq926xz6/
You can use clearInterval:
if (score < 10) {
clearInterval(repeater);
repeater = setInterval(spawnEnemy, 1000);
}
if (score => 10) {
clearInterval(repeater);
repeater = setInterval(spawnEnemy, 500);
}
But it depends on the context. If this snippet is executed more often, than it has to be, you will need some kind of mechanism to prevent it from resetting your interval all the time.
But there is (as I wrote in the comment to the question) no way to use clearInterval and change the interval itself. At least not without replacing it by a new interval as shown above.
You can use a game loop and track the spawn state in an enemy class:
// press f12 so see console
function Enemy() {
this.spawned = false;
this.spawnOn = 20;
this.tick = function () {
this.spawnOn = this.spawnOn - 1;
if (this.spawnOn == 0) {
this.spawned = true;
}
}
this.goBackToYourCage = function () {
this.spawnOn = Math.floor(Math.random() * 50) + 1;
this.spawned = false;
}
}
var enemy = new Enemy();
window.setInterval(function () {
enemy.tick();
if (enemy.spawned) {
console.log('spawned');
enemy.goBackToYourCage();
console.log('Next spawin in :' + enemy.spawnOn);
}
}, 100);
http://jsfiddle.net/martijn/qxt2fe8y/2/

Can't Get Variable to Add Properly

I have a variable++; in an if/else statement (it being in the else part). It's supposed to add 1 to a score of how many wrong guesses one has.
For some reason it never adds just one, it will also add numbers ranging from 3 to 7 whenever I submit a 'guess'. Can you guys tell me if I'm looping wrong or something? Please try to explain in detail.
EDIT: I realized part of the problem. The tries++; is actually looping once for each letter [var]choice didn't match or equal. For instance if I enter "a" for "apple" tries++; will loop four times because of the four other characters. So how do I get it to only loop only once instead of adding one for each missed character?
This is my code.
// JavaScript Document
var words = new Array("apple","orange","banana","lime","mango","lemon","avacado","pineapple","kiwi","plum","watermelon","peach");
var randomNum;
var word;
var tries = 0;
$('#guess').prop('disabled', true);
$(function(){
$('#start').click(function(){
$('#guess').prop('disabled', false);
word = "";
randomNum = Math.floor(Math.random() * words.length)
for (var i =0; i < words[randomNum].length; i++) {
word += "*";
}
console.log(words[randomNum]);
$('#word').html(word);
});
$('#guess').click(function guess(){
var choice = $('#letter').val().toLowerCase();
for (var i =0; i < word.length; i++) {
if (words[randomNum].charAt(i) == choice) {
word = word.substr(0, i) + choice + word.substr(i + 1);
}
if (words[randomNum].charAt(i) !== choice) {
tries++;
}
}
if (tries < 7) {
$('#tries').html(tries)
} else if (tries >= 7)
$('#tries').html("YOU LOSE");
$('#word').html(word);
$('#' + choice).css("background-color", "red");
});
});
Got it working!
The issue is related to the tries variable, inside the for loop (per letter). In order to see the odd behavior add a console.log(tries); in your code, inside the loop and you will see. At first time it will increase in 1 then the value will change completely (I will suggest some debugging here to understand what's going on with more accuracy since I did this real quick). The solution is increasing the variable out of the for loop context to make it work (I did this in the provided example from the bottom).
By the way, it seems that you are trying to implement a "Hangman" game and to be honest, when implementing those things you need to be really organized.
I fixed your issue, improved the code a lot and also considered other possible game scenarios like:
Play Again
Game Over
Win
Go Back
Please take a look. Just to know, HTML and CSS are just improvisations made for this example, some improvements are needed so just take them as a reference.
Update: What you had put in the EDIT part from your post is correct.
You can run this script at the bottom.
// Game variables
var GAME_WORDS = [ // List of words available when playing
'apple',
'orange',
'banana',
'lime',
'mango',
'lemon',
'avacado',
'pineapple',
'kiwi',
'plum',
'watermelon',
'peach'
],
GAME_MASKED_WORD = '', // Stores the masked word to be discovered
GAME_SELECTED_WORD = '', // Stores the readable word
GAME_PLAYER_ATTEMPTS = 0, // Stores player attempts when failing
GAME_RANDOM_NUMBER = 0, // Random number to pick a word
GAME_MAX_ATTEMPTS = 7, // Max. player attempts before a game over
GAME_UI_COMPONENTS = { // UI components declaration
start: $('#start'),
reset: $('#reset'),
back: $('#back'),
guess: $('#guess'),
msg: $('#msg'),
word: $('#word'),
letter: $('#letter')
},
GAME_UI_SECTIONS = { // UI sections declaration
menu: $('#menu'),
game: $('#game')
};
$(function() {;
var ui = GAME_UI_COMPONENTS;
// Initialize game
init();
// Start button handler
ui.start.on('click', function(e) {
start();
});
// Guess button handler
ui.guess.on('click', function(e) {
guess();
});
// Play Again button handler
ui.reset.on('click', function(e) {
reset();
start();
});
// Go Back button handler
ui.back.on('click', function(e) {
init();
});
});
/**
* Used to initialize the game for first time
*/
function init() {
var sections = GAME_UI_SECTIONS;
sections.menu.show();
sections.game.hide();
reset();
};
/**
* Used to start the game
*/
function start() {
var ui = GAME_UI_COMPONENTS,
sections = GAME_UI_SECTIONS,
words = GAME_WORDS;
sections.menu.hide();
sections.game.show();
GAME_RANDOM_NUMBER = Math.floor(Math.random() * words.length);
for (var i = 0; i < words[GAME_RANDOM_NUMBER].length; ++i) {
GAME_MASKED_WORD += '*';
}
GAME_SELECTED_WORD = words[GAME_RANDOM_NUMBER];
ui.word.html(GAME_MASKED_WORD);
ui.letter.focus();
};
/**
* Guess button handler
*/
function guess() {
var ui = GAME_UI_COMPONENTS,
words = GAME_WORDS,
matches = false,
choice;
// Clean messages each time player do a guess
showMsg('');
if (ui.letter && ui.letter.val()) {
choice = $.trim(ui.letter.val().toLowerCase());
}
if (choice) {
for (var i = 0; i < GAME_MASKED_WORD.length; ++i) {
if (words[GAME_RANDOM_NUMBER].charAt(i) === choice) {
GAME_MASKED_WORD = GAME_MASKED_WORD.substr(0, i) + choice +
GAME_MASKED_WORD.substr(i + 1);
matches = true;
}
}
if (!matches) {
++GAME_PLAYER_ATTEMPTS;
}
} else {
showMsg('Please type a letter.');
}
// Show attempts left if more than zero
if (GAME_PLAYER_ATTEMPTS > 0) {
showMsg('You have ' +
(GAME_MAX_ATTEMPTS - GAME_PLAYER_ATTEMPTS) +
' attempt(s) left.');
}
// Check game status each time doing a guess
if (isGameOver()) {
lose();
} else if (isGameWin()) {
win();
} else {
ui.word.html(GAME_MASKED_WORD);
}
ui.letter.focus();
};
/**
* Used to set all game variables from the scratch
*/
function reset() {
var ui = GAME_UI_COMPONENTS;
GAME_MASKED_WORD = '';
GAME_PLAYER_ATTEMPTS = 0;
GAME_RANDOM_NUMBER = 0;
showMsg('');
ui.guess.show();
ui.letter.val('');
ui.word.html('');
};
/**
* Handler when player lose the game
*/
function lose() {
var ui = GAME_UI_COMPONENTS;
showMsg('You Lose!');
ui.word.html(GAME_SELECTED_WORD);
ui.guess.hide();
};
/**
* Handler when player win the game
*/
function win() {
var ui = GAME_UI_COMPONENTS;
showMsg('You Win!');
ui.word.html(GAME_SELECTED_WORD);
ui.guess.hide();
};
/**
* Use to print UI messages for the player
*/
function showMsg(msg) {
var ui = GAME_UI_COMPONENTS;
ui.msg.html(msg);
};
/**
* Check game status, if player is going to lose the game
* #returns Boolean
*/
function isGameOver() {
return (GAME_PLAYER_ATTEMPTS >= GAME_MAX_ATTEMPTS);
};
/**
* Check game status, if player is going to win the game
* #returns Boolean
*/
function isGameWin() {
return (GAME_MASKED_WORD === GAME_SELECTED_WORD);
};
.btn {
cursor: pointer;
}
span#msg {
color: red;
font-weight: bold;
}
.text {
font-size: 3em;
}
input#letter {
width: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="wrapper">
<div id="menu">
<span class="text">Hangman!</span>
<br><br>
<img src="http://img3.wikia.nocookie.net/__cb20130207191137/scribblenauts/images/0/01/Hangman.png" height="200" width="120"/>
<br><br>
<input type="button" class="btn" id="start" value="Start Game"/>
</div>
<div id="game">
<span id="msg"></span>
<br><br>
Letter: <input type="text" id="letter" value="" maxlength="1"/>
<br><br>
<input type="button" class="btn" id="guess" value="Guess"/>
<input type="button" class="btn" id="reset" value="Play Again"/>
<input type="button" class="btn" id="back" value="Go Back"/>
<br><br>
Word: <div id="word" class="text"></div>
</div>
</div>
Hope this helps.
try this one:
Modify guess click handler like this:
$('#guess').click(function guess(){
var choice = $('#letter').val().toLowerCase(),
found = false;
for (var i =0; i < word.length; i++) {
if (words[randomNum].charAt(i) == choice) {
word = word.substr(0, i) + choice + word.substr(i + 1);
found = true
}
}
if(!found){
tries++;
}
if (tries < 7) {
$('#tries').html(tries)
} else if (tries >= 7){
$('#tries').html("YOU LOSE");
}
$('#word').html(word);
$('#' + choice).css("background-color", "red");
});
Also on start reset the tries:
$('#start').click(function(){
$('#guess').prop('disabled', false);
word = ""; tries = 0;

Categories