How to make if statement true only once? - javascript

How do I make an if statement run only once. I am making a game in javascript and once the users score is 5 I want to add a new enemy into the array. The problem I am having is once the if statement is true it keeps adding new enemies over and over until the whole screen is covered with enemies. I want it to add only 1 new enemy when score is 5 then another when score is 10 and so on. I cannot think of a way to accomplish this. Thank You.
Sketch.js
var score = 0;
//3 three enemies once game starts
function StartingEnemies() {
for (var i = 0; i < 2; i++) {
enemies[i] = new BasicEnemy();
}
}
//add new enemies into the array
function spawnNewEnemies() {
enemies.push(new BasicEnemy());
}
if (score == 5) {
spawnNewEnemies();
}

var addNew=true;
if (score == 5 && addNew) {
spawnNewEnemies();
addNew=false;
}
If you are running the code inside of a function, make sure that addNew is declared somewhere that it will persist between calls.

You need a simple latch. Try adding a boolean variable called isEnemyAddedAtFive and set it to false as it's default value.
var isEnemyAddedAtFive = false;
Then at your check point test this value and if not latched, act and latch:
if( score == 5 && !isEnemyAddedAtFive ) {
addEnemy();
isEnemyAddedAtFive = true;
}
Good Luck!

if ( score != 0 && score % 5 == 0) {
spawnNewEnemies();
}
Try this one.

This is a little more complex than you are currently coding. There are a few ways you could interpret this. Firm your requirements.
Do you want to only add an enemy if the score is divisible by 5... Meaning only when the score ends in 0 or 5 (5, 10, 15, 20, etc):
If (score % 5 == 0) {
enemies.push(new BasicEnemy());
}
Otherwise you may need to track a total score and a level/segmented score representing the score since the program last took action on the game.
// Initialization
var totalScore = 0;
Var currents core = 0;
// Game event loop
while (player.lifeState > 0) {
// Check current score is 5 or more on every iteration of the game event loop
if (currentScore >= 5) {
// Handle score
spawnNewEnemies();
// Update scoring
totalScore += currentScore;
// Reset currentScore (or not if you want to do more stuff in the level before resetting but this may change the above logic)
currentScore = 0;
}
Your logic will get more complex as you as more features. The best first step is to define clear requirements before coding as one retirement may influence how you implement another

//post this snippet at some top level of your code.
var onceMap = {};
function once(key) {
if (onceMap[key]) {
return false;
} else {
onceMap[key] = true;
return true;
}
}
var score = 10;
//do this in your task function
function task() {
if (score >= 5 && once("score5")) {
console.log("score 5 action");
}
if (score >= 10 && once("score10")) {
console.log("score 10 action");
}
}
task();
task();
task();

What comes first to mind after seeing your code is that:
It should be
for (var i = 0; i < 3; i++)
for 3 enemies
You are calling your code (i.e .js file multiple times). This means that score resets to 0 each time it is called and score==5 condition occurs multiple times.
Solution:
Change your logic such that the .js file is called only once and store the score for the entire duration of the game.
Hope this helps

!( score != 0 && score % 5 == 0) || spawnNewEnemies()
//how it functions
!true || run()
I'll have to admit this is a bit abstract. But what this does is if the score is true, it forces into false and runs spawnNewEnemies. If the score isn't true. It forces into true and don't run the false condition.
However id suggest a function edit:
var spawnNewEnemies =scored=> !(scored !=0 && scored%5===0) || enemies.push(new BasicEnemy());
spawnNewEnemies(score);
SpawnNewEnemies now takes a score parameter. But also is an arrow function that can be used for quick one-liners. Since score is a dependency, itll run on that condition. If the base score is 0 and also divisible by 5, the condition returns true, but the "bang" (!) operator forces it into false, and executes the new enemies. If the score isn't divisible by five, itll return false but the bang flips it and will not return the OR false arguement.

Related

How to Iterate the next 10 in a while loop

I am trying to iterate a count of every 10 in a while loop. The code below counts 200 10 times and then stops, the reason it stops is that I need to store the first 10 in a spreadsheet, but that is another problem to solve, right now, I am not sure how to go about moving onto the next 10 counts taken from the first 10 count in the while loop below.
while (go) {
data = getRecordsByPage(i,200,token,module);
if (Number(data.info.count) < 200) {
go = false;
};
if (i == 10) {
go = false;
while(go = false)
{
Utilities.sleep(10000)
}
if(Utilities.sleep == 10000)
{
go = true;
}
}
rows = Number(rows) + Number(data.info.count);
i++;
Logger.log(rows)
}
Also, please let me know if having a nested while loop in this is loop a good way to restart the loop again with the timer before it restarts.
How about using modulo?
replace if (i == 10) { by if (i%10 == 0) {
This way, it will enter in your if statement every multiple of 10

JavaScript loop using set amount of steps while skipping specific step

I am trying to create a loop that allows you to go up in increments of one each time using "x" amount of steps while skipping a specific step. example 1 would be you have 2 actions and need to skip step 2. so you would go from 0 to 1 and then 1 to 3. example 2 would be you have 3 actions and need to skip step 3 so you could either go from 0 to 1, wait 1 round, then go from 1 to 4 since you would be skipping up two. or you could wait at 0 then skip to 2 and then skip to 5.
i know I am close using a while loop with continue but it doesn't quite work like expected.
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total <= step) {
total += 1
if (total === bad) {
continue;
}
total += 1
return total
}
}
Hello and welcome #jaronow!
First, continue skips you to the next iteration of the while. So what you've written here...
if (total === bad) {
continue;
}
total += 1
...actually means, "If this is a bad number of steps, then skip adding 1." But you mean the opposite, don't you?
if (total === bad) {
total += 1
}
This now says, "If this is a bad number of steps, add another 1." There, so now we have
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total <= step) {
total += 1
if (total === bad) {
total += 1 // Put this here instead of continue.
}
return total
}
}
Now, where you put this is odd:
return total
This actually exits the entire function the first time it's encountered. Surely you mean to calculate total by running through your loop as many times as needed, then return the result at the end, like this:
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total <= step) {
total += 1
if (total === bad) {
total += 1
}
}
return total // Moved this out.
}
Finally, there's two subtle issues (noticed the second one later). First, if you take that "extra step" because you've encountered a bad step, you need to increase step as well, since it's the maximum number of steps you plan to take. But also, once you reach that number of steps, you don't want to enter the loop again and add another to total, so you need to use < instead of <=. (You'll find it a common pattern in programming that when you intend to do things N times, you write your loops saying < N, not <= N.)
function maxStep(n, k) {
let step = n
let bad = k
let total = 0
while (total < step) {
total += 1
if (total === bad) {
total += 1
step += 1 // Add this.
}
}
return total
}
Otherwise, your total will always end up at the original number of steps.
There are other shorter, possibly more clever ways of solving this problem, but I'm aiming to teach by sticking to your formulation.
Not something you have to care about, but in case you want to see, a seasoned programmer may "refactor" your code this way:
function getStepsTaken(desiredStepsToTake, badNumberOfSteps) {
let stepsToTake = desiredStepsToTake
// let bad = k (don't need this line)
let stepsTaken = 0
while (stepsTaken < stepsToTake) {
stepsTaken += 1
if (stepsTaken === badNumberOfSteps) {
stepsTaken += 1
stepsToTake += 1
}
}
return stepsTaken
}
You may find it ugly, and indeed it's much more verbose, but it's always better to make things very clear, even if just for yourself and you rename the variables later.
Solid attempt though, keep it up.

Algorithm : finding nearby value the fastest way

I have an array of sorted numbers, and a starting value. For the sake of simplicity, let's say the array has values from 1 to 20, and the starting value is 10.
The value to find can change every 5 seconds, based on user input. It can either increase or decrease and it always keeps in the range of values of the table.
The only thing I cannot know is whether the value is increasing or decreasing. I have come up with the (very) simple algorithm below.
Can you think of a way to improve it ?
Ideally, I think the best approach would be to run the two for loops simultaneously and return when value is found... Using workers for example ?
In my example, the "going down" for loops is exhausted before "going up" starts running. Which, idealy, shouldn't happen, since I'm trying to spread tries -1/+1 each time.
Btw : the reason why I'm trying to do this is because I have to run quite heavy functions in the for loops. The code is running in node.js context.
Here's a JSFiddle and the code below
const attempts = document.getElementById('attempts');
let attemptsCount = Number(attempts.textContent);
const lastValue = 10;
const valueToFind = 16; //this must be found in the least possible number of attempts
const table = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
const lookup = () => {
for (var i = lastValue; i > 0; i--) {
if (table[i] == valueToFind) {
alert('Found going down');
return;
} else {
attemptsCount++;
attempts.textContent = attemptsCount;
}
}
for (var i = lastValue; i < table[table.length-1]; i++) {
if (table[i] == valueToFind) {
alert('Found going up');
return;
} else {
attemptsCount++;
attempts.textContent = attemptsCount;
}
}
}
//find new value
lookup();
Right now, each for loop you have runs async from one another...so one side will always finish before the other side starts...which is not ideal.
Remember that for loops are set up to initialize, check if bool statement = true, and set next step...so like if statements, you can implement multiple statements in each scenario.
Reducing the loop attempts can be simple as doing it at the same time:
const lookup = () => {
for (var up = lastValue, down = lastValue-1; up < table[table.length-1] || down > 0; up++, down--) {
if (up < table[table.length-1] && table[up] == valueToFind) {
alert('Found going up');
return;
} else if (down > 0 && table[down] == valueToFind) {
alert('Found going down');
return;
} else {
attemptsCount++;
attempts.textContent = attemptsCount;
}
}
Your JSFiddle updated

Traverse an object or array to determine if elements fit within ranges

I am building a decorator for arrays of items, the array of objects is meant to be slotted into a defined range of values if it fits there.
Currently, I am doing this using some conditionals to check for the range but the code does not feel clean enough to me.
Does anyone have any suggestions about how write this code in a more concise and expandable way?
Example of current setup...
thingsToSort.forEach(function(thing) {
if (thing > 1 || thing < 3) {
// set the item to 1
}
if (thing > 3 || thing < 5) {
// set to 3
}
})
Note: I am really looking for a better way to loop through this logic and determine if object falls in the range.
One another implementation.
Created a function to represent the Range, Range
A function to identify the range and take appropriate action. setcompareRange
Notice the usage of the some method in the function compareRange. Since a number can be found in one range only, All the ranges are not evaluated and till the matched range traversal is done.
function Range(min, max){
this.min = min;
this.max = max;
}
var rangeArray = [ new Range(1,3), new Range(3,5)];
function compareRange(c,i,arr){
var result = rangeArray.some(x=> {
return setcompareRange(c, x.min, x.max)
});
}
function setcompareRange(thing, min, max){
if (thing > min && thing < max) {
// set the item to 1
console.log("set thing = " + thing + " in range = " + min);
return true;
}
}
var thingsToSort = [2,4];
thingsToSort.forEach(compareRange);
I would first double-check your logic...
thingsToSort.forEach(function(thing) {
This conditional will set ANYTHING greater than 1 to 1, and ignore the second condition (thing < 3):
if (thing > 1 || thing < 3) {
// set the item to 1
}
You should be using an && operator to AND these two conditions:
if (thing > 1 && thing < 3) {
// set the item to 1
}
The same thing goes for this conditional which will set ANYTHING greater than 3 to 3.
if (thing > 3 || thing < 5) { //should be &&
// set to 3
}
})
You are also not breaking the loop after meeting a conditional. This means that even though you have already determined that a thing meets the first condition, you are still checking to see if it meets the other conditions. This wastes resources. Use else if to prevent this:
if (thing > 1 && thing < 3) {
// set the item to 1
}
else if (thing > 3 && thing < 5) {
// set to 3
}
Other than that, it's already pretty clean. This is very similar to the classic fizzbuzz problem, of which, there are many possible refactorings

How to make an infinite for loop (for(;;)) not crash?

I'm new to JS, so most of my code hasn't worked. I've made a program to find out every prime number, but every time I use it, it crashes. Is there any way to make this code not crash upon running?
var i = 0;
for (;;) {
if (i % 2 === 0 || i % 3 === 0 || i % 5 === 0 || i % 7 === 0) {
i++;
}
else {
return i;
i++;
}
}
The correct approach is to use a single timer. Using setInterval, you can achieve what you want as follows:
window.onload = function start() {
primes();
}
function primes() {
var i = 0;
window.setInterval(function () {
if (i % 2 === 0 || i % 3 === 0 || i % 5 === 0 || i % 7 === 0) {
i++;
} else {
console.log(i);
i++;
}
}, 1000); // repeat forever, new value every 1 second
}
This will print the values to the console once a match is found (It does a check every second). But you can adjust this on the second parameter of the setInterval function.
If you want the results on the actual page, you can replace the console.log() with document.createTextNode().
Also, i have not checked this or know if the algorithm is right. Just adapted from your code.
List of fixes:
You manually update i and use a blank for loop instead of using the for loop normally, but having the middle condition always return true (a while loop could be used here also, but would still require manually updating i) as you don't plan on stopping. However, you can actually just put the whole thing in a timer instead of a loop, like #Leonel Atencio did.
You use return outside of a function, and if you did put this code inside of a function, it would just return the first prime number every time, so it would always return 1.
The formula is incorrect, only checking for some examples of primes; As #Alexandru-Ionut Mihai said, 121 would be considered prime, even though it is 11x11.
Fixed:
var primes = [];
var i = 1; //Start at 2; since "i" is incremented at the start of the function, this won't start it at 1, which would cause problems (the array would only have 1 in it, since all other whole numebrs are divisible by one)
setInterval(primeFunc,100);
function primeFunc(){
i++; //Increment current number
isPrime=true; //Assume prime
for(var j=0;j<primes.length;j++){ //Rule out non-primes with the power of modulo
if(i%primes[j]==0) { //If the current number can be divided (is divisible) by any previous prime...
//...then it's not a prime, so cancel any further chacks and move on
isPrime=false;
break;
}
}
if(isPrime){
//The current number is not divisible by any other primes, so it is itself a prime; if it was divisible, isPrime would be set to false by our loop above
primes.push(i);
output.innerHTML=primes;
}
}
<span id="output"></span>

Categories

Resources