How to change an objects properties right after a condition is met? - javascript

I am trying to make a button go from .disabled = true to .disabled = false. I am making a Yahtzee clone for fun, and you have to choose a score to take on your third roll, and then after that the button will be unlocked and you can roll again. Here's what I had, but it crashes. I wanted to make a while statement until a score is selected. ptsss is the amount of scores that have been selected. (i.e. third roll should equal 1 score entered)
if(rollcount == 3){
while (ptsss * 3 < rollcount){
document.getElementById("rollbutton").disabled = true;
if (ptsss * 3 == rollcount){
document.getElementById("rollbutton").disabled = false;
break;
}
}
}
}

Try removing the while loop and (possibly) rewrite the code as a function to enable/disable the roll button as required. E.G.
function checkRollButton( rollcount, ptsss) {
if(rollcount == 3) {
document.getElementById("rollbutton").disabled = ptsss != 1;
}
}
Then call (or inline the code for) checkRollbutton in event handlers that update rollcount and/or ptsss.
As commented, the value of ptsss cannot be changed by other code while the while loop is running, because JavaScript is single threaded.
I've modified the statement that enables/disables the roll button according to my understanding of the design, please check it before use.

Loops in JavaScript are not like loops in some other languages.
If the condition in the loop is not being modified within the loop itself, it won't be modified (unless possibly it's happening inside an asynchronous function).
Also you shouldn't constantly use the getElement in a loop anyways.
The way to achieve the general functionality of what a while loop is in other languages, in JavaScript, is to use an interval.
So based on that your updated code can look something like this (not sure where the first if statement is being called from so I took it out, also the nested if statement would have never been called because it only takes effect if it's condition is false, so I changed that as well):
var roll=document.getElementById("rollbutton")//make sure this is called after that element has loaded
var inter=setInterval(function(){
if (ptsss * 3 == rollcount){
roll.disabled = false;
clearInterval(inter)
//Similar to break in while loop, can restart interval later after this
}
if (ptsss * 3 < rollcount){
roll.disabled = true;
}
}
},1000/30//30 FPS
);

Related

Create an html button to start the routine and use this function to write out to the HTML Page the Result

Here is my javascript loop
for (var i=1; i <= 100; i++)
{
if (i % 15 == 0)
console.log("DuckGoose");
else if (i % 3 == 0)
console.log("Duck");
else if (i % 5 == 0)
console.log("Goose");
else
console.log(i);
}
Im just recently getting into learning html , and java script in my attempts to become a full stack developer by the end of the summer.. Here im trying to use an html button to start/stop this loop and use the function listed below the number 3. Below is what I have so far on the HTML side. Im really hung up and stuck on how to start/stop this loop using this button. Can someone teach me the best way to do this in a beginner way? Still learning. Thanks
<body>
<div>
<button>Click me</button>
</div>
</body>
3
function write (o) {
var el = document.createElement('pre');
el.innerHTML = JSON.stringify(o, undefined, 2);
document.body.appendChild(el);
}
So there is something to be aware of with a for loop, you usually don't stop them with a button click. Once a for loop has started, it will continue to run until 1 of 2 things happen, either the loop's condition evaluates to false, or specifically in code it's told to do something different (either a break or continue statement). So you could have the button click kick off the starting of the loop, but that loop will continue to run until it's done. Using jQuery, it would look something like this.
$(document).on('click', '#duckDuckGoose', function() {
RunDuckDuckGoose();
});
function RunDuckDuckGoose() {
for (var i=1; i <= 100; i++)
{
if (i % 15 === 0)
console.log("DuckGoose");
else if (i % 3 === 0)
console.log("Duck");
else if (i % 5 === 0)
console.log("Goose");
else
console.log(i);
}
}
Now if you REALLY need a button to stop the execution, there are a couple things to keep in mind.
The for loop will go through all 100 elements VERY quickly. So you may want to put something in there to slow down the loops, (or increase the amount of loops) that way you can actually see the stop button work.
In order for the for loop to stop on the button click, the click handler will have to trigger some variable (declared outside of the for loop) that the for loop can look at.
Unfortunately, looping the way I showed you blocks the UI so you can't stop the loop anyway with a button click, so you'd have to look into looping async, see this article for ways to do that.
I hope this helps or at least points you in the right direction. Best of luck on your new journey!

Getting the condition of a while loop to print out once false

I am doing an exercise on an online course to learn Javascript. This is only the first one and I am having issues, so I really want to understand it before I progress.
The question is this:
complete the while loop in the editor so it will print out "I'm learning while loops!". Do this by adding the condition between the parentheses—don't change line 5, or you could get an infinite loop!
The code is:
var understand = true;
while(){
console.log("I'm learning while loops!");
understand = false;
}
I tried adding this to the condition:
while(understand === 0){
But I am getting this error
Oops, try again. It looks like you didn't print the string to the console. Check your loop syntax!
What am I doing wrong in my condition? Could someone please elaborate, so I can learn the key fundamentals to this. Thanks!
The example before this exercise:
var coinFace = Math.floor(Math.random() * 2);
while(coinFace === 0){
console.log("Heads! Flipping again...");
var coinFace = Math.floor(Math.random() * 2);
}
console.log("Tails! Done flipping.");
Edit---update:
You may have noticed that when we give a variable the boolean value true, we check that variable directly—we don't bother with ===. For instance,
var bool = true;
while(bool){
//Do something
}
is the same thing as
var bool = true;
while(bool === true){
//Do something
}
but the first one is faster to type. Get in the habit of typing exactly as much as you need to, and no more!
If you happen to be using numbers, as we did earlier, you could even do:
It's while(understand === true)
Because the loop will fire the first time, as understand is already set to true. Then, as it's firing, it will set understand to false- so the next time it tries to fire the loop the condition will fail and it won't continue. This way, you're getting one execution of the loop- thus printing only one time.
If you had code that looks like this
while(true){
console.log("I'm learning while loops!");
understand = false;
}
you would get an infinite loop! The loop would just keep going because the conditional will always be true. Now if only there were some way, like a variable in the conditional, to make the conditional false.

Is it possible to have two Else conditions run simultaneously?

I am creating a game that when the play button is clicked, the timer starts. When my time is 0 I want to the paragraph with #timeline to be replaced with different text, which works perfectly. However how can I simultaneously add a .class to the replacement text so I can style "Your time is up!" differently when it is displayed.
var secondsLeft = 20;
function startTimer(){
setInterval(myTimer, 1000);
}
function myTimer(){
if(secondsLeft!=0){
document.getElementById("time").innerHTML = secondsLeft-=1;
} else {
document.getElementById("timeLine").innerHTML = "Your time is up!";
}
}
No. You cannot. With any programming language, you need to follow the basics of an if statement. If statements can have numerous else conditions, but only one condition will be met. This is how control flow is accomplished. It will keep going down the list until one condition is met. In your case, the first condition with "time" is the proper code that would be run.
As far as styling goes for time === 0, you should try putting both in the same else condition and see if that is what you are looking for.

JavaScript: an if statement is changing outcomes of a random generator?

Basically I'm creating a program similar to a blackjack program where two cards are dealt according to a random number generator, with the possibility of the same card being dealt twice at the same time (i.e. two Queen of hearts showing up at once) and I want to create a counter of how many times that event occurs, but when I implement an if statement, it affects the outcome so that the two cards are ALWAYS the exact same...can someone tell me what I'm doing wrong here? The code is as follows:
function dealHand() {
var randomCardOne = Math.floor ((Math.random() *13) +2);
var randomCardTwo = Math.floor ((Math.random() *13) +2);
if (randomCardOne = randomCardTwo) {identicalCards()};
}
var identicalPairs = 0;
function identicalCards(){
document.getElementById("identical").value=++identicalPairs;
}
You are assigning the value of one card to another
if (randomCardOne = randomCardTwo) {identicalCards()};
should be
if (randomCardOne == randomCardTwo) {identicalCards()};
In the first case you are simply evaluating if randomCardOne is "truthy" after being asigned the value of randomCardTwo.
Consider if you might want to use === instead of == since
2 == '2' // yields true
2 === '2' // yields false
It's not an issue in this case but it might be in others so it's good to be aware of this. I try to stick with === since it is more strict.
You're using =, that's an assignment operator in JavaScript. You should be using ==
e.g.
if (randomCardOne == randomCardTwo) {identicalCards()};

Optimizing Javascript Loop for Wheel Game

I have a game I'm creating where lights run around the outside of a circle, and you must try and stop the light on the same spot three times in a row. Currently, I'm using the following code to loop through the lights and turn them "on" and "off":
var num_lights = 20;
var loop_speed = 55;
var light_index = 0;
var prevent_stop = false; //If true, prevents user from stopping light
var loop = setTimeout(startLoop, loop_speed);
function startLoop() {
prevent_stop = false;
$(".light:eq(" + light_index + ")").css("background-color", "#fff");
light_index++;
if(light_index >= num_lights) {
light_index = 0;
}
$(".light:eq(" + light_index + ")").css("background-color", "red");
loop = setTimeout(startLoop, loop_speed);
}
function stopLoop() {
clearTimeout(loop);
}
For the most part, the code seems to run pretty well, but if I have a video running simultaneously in another tab, the turning on and off of the lights seems to chug a bit. Any input on how I could possibly speed this up would be great.
For an example of the code from above, check out this page: http://ericditmer.com/wheel
When optimizing the thing to look at first is not doing twice anything you only need to do once. Looking up an element from the DOM can be expensive and you definitely know which elements you want, so why not pre-fetch all of them and void doing that multiple times?
What I mean is that you should
var lights = $('.light');
So that you can later just say
lights.eq(light_index).css("background-color", "red");
Just be sure to do the first thing in a place which keeps lights in scope for the second.
EDIT: Updated per comment.
I would make a global array of your selector references, so they selector doesn't have to be executed every time the function is called. I would also consider swapping class names, rather than attributes.
Here's some information of jQuery performance:
http://www.componenthouse.com/article-19
EDIT: that article id quite old though and jQuery has evolved a lot since. This is more recent: http://blog.dynatrace.com/2009/11/09/101-on-jquery-selector-performance/
You could try storing the light elements in an array instead of using a selector each time. Class selectors can be a little slow.
var elements = $('.light');
function startLoop() {
prevent_stop = false;
$(elements[light_index]).css('background-color', '#fff');
...
}
This assumes that the elements are already in their intended order in the DOM.
One thing I will note is that you have used a setTimeout() and really just engineered it to behave like setInterval().
Try using setInterval() instead. I'm no js engine guru but I would like to think the constant reuse of setTimeout has to have some effect on performance that would not be present using setInterval() (which you only need to set once).
Edit:
Curtousy of Diodeus, a related post to back my statement:
Related Stack Question - setTimeout() vs setInterval()
OK, this includes some "best practice" improvements, if it really optimizes the execution speed should be tested. At least you can proclaim you're now coding ninja style lol
// create a helper function that lend the array reverse function to reverse the
// order of a jquery sets. It's an object by default, not an array, so using it
// directly would fail
$.fn.reverse = Array.prototype.reverse;
var loop,
loop_speed = 55,
prevent_stop = false,
// prefetch a jquery set of all lights and reverses it to keep the right
// order when iterating backwards (small performance optimization)
lights = $('.light').reverse();
// this named function executes as soon as it's initialized
// I wrapped everything into a second function, so the variable prevent_stop is
// only set once at the beginning of the loop
(function startLoop() {
// keep variables always in the scope they are needed
// changed the iteration to count down, because checking for 0 is faster.
var num_lights = light_index = lights.length - 1;
prevent_stop = false;
// This is an auto-executing, self-referencing function
// which avoids the 55ms delay when starting the loop
loop = setInterval((function() {
// work with css-class changing rather than css manipulation
lights.eq( light_index ).removeClass('active');
// if not 0 iterate else set to num_lights
light_index = (light_index)? --light_index:num_lights;
lights.eq( light_index ).addClass('active');
// returns a referenze to this function so it can be executed by setInterval()
return arguments.callee;
})(), loop_speed);
})();
function stopLoop() {
clearInterval(loop);
}
Cheers neutronenstern

Categories

Resources