How to make for loop happen every set amount of time? - javascript

I need to add "momentum" to an object on a grid. The player can control the object as long as he hold the key down, however, I want the ability to press the key one time and the object will keep going in the direction of the key until he hits the border. I have create a simple for loop that works, however because it happens so fast the object just kind of "teleports" to the border. I want the for loop to happen for example every second. Here is a short part of my code:
case "ArrowRight":
if (snakex + 1 == 26) {
temp += 1;
}
else {
for (let i = snakex; i < 26; i++) {
snakex += 1;
snake.style.gridArea = snakey + "/" + snakex;
}
}
break;
The game board is a 25x25 grid, if the fact that going to the right will result in going out of the board, the function will not do anything (temp is there for filling out a "fail mechanic" that I didn't add).
Without the for loop, the player needs to hold down the right key. This for loop makes it so the player needs to press it once, however it happens so fast it "teleports" like I said. Is it possible to make this loop happen every second, for example?
Any help would be appreciated. Thanks in advance!

you can control the speed of a loop by wrapping it in an async function, then you can write a custom function for sleep and await the sleep function at the beginning of every loop.
async function test() {
for(let i =0; i < 10; i++ {
await sleep(1000)
//logic goes here
}
}
function sleep(ms: number) {
return new Promise(r => setTimeout(r,ms))
}

Related

How can I set a for loop with settimeout that iterates backwards?

I may be approaching this in completely the wrong way, as I'm a bit of a novice when it comes to javascript, but essentially what I'm trying to do (for a bit of fun) is to have a cell of a table change colour onclick, then have the cells to the north, east, south, and west change to a different colour in sequence (think of the bomb effect in bomberman).
So far, I've managed to get the south direction to work using the following code:
function timeOutDown(i) {
let bubbleRowPositive = col + rowArray[i];
let bubbleRowPositiveId = document.getElementById(bubbleRowPositive);
setTimeout(function() {
bubbleRowPositiveId.style.backgroundColor = "#AA3333";
},i * 50);
}
for (let i=row; i<colArray.length; i++) {
timeOutDown(i);
}
For context, there are 15 rows and 15 columns of evenly sized table cells, with ID's like "a1" and "h14".
However, the issue I'm coming across is that the inverse will still iterate upwards, even when reversing the for loop and I can't figure out why:
function timeOutUp(k) {
let bubbleRowNegative = col + rowArray[k];
let bubbleRowNegativeId = document.getElementById(bubbleRowNegative);
setTimeout(function() {
bubbleRowNegativeId.style.backgroundColor = "#AA3333";
console.log(`Index: ${k}, Row Num: ${rowArray[k]}`);
},k * 50);
}
for (let k=row-2; k>=0; k--) {
timeOutUp(k);
console.log(k);
}
I had started by using the same function to handle both for loops, that didn't work, so I attempted this method using 2 separate functions.
Is there an easier way to go about this?
Even though your for loop reversed, it still passes in the same index for every iteration, and that index is used to compute the delay it gets. So no matter what, the item at index 0 gets 0*50 milliseconds delay, regardless whether it happens first or last. You still need your original counter in order to define their ordered index. You could solve it like this:
function timeOutUp(k, i) {
let bubbleRowNegative = col + rowArray[k];
let bubbleRowNegativeId = document.getElementById(bubbleRowNegative);
setTimeout(function() {
bubbleRowNegativeId.style.backgroundColor = "#AA3333";
console.log(`Index: ${k}, Row Num: ${rowArray[k]}`);
},i * 50);
}
for (let k=row-2, i = 0; k>=0; k--, i++ ) {
timeOutUp(k, i);
console.log(k, i);
}
I just added 1 variable: i back in, that counts up. It gets passed to timeOutUp to compute the actual delay in the order you intend.

Why doesn't setTimeout() work in my sorting function?

UPDATE
I could not figure out what the problem was to this, but I found a solution to my overall problem. I simply changed my bubbleSort() algorithm to only utilize for-loops and that appeared to work. Thank you for the help!
I am currently learning javaScript and React. As a practice project, I am attempting to create a sorting algorithm visualizer. For a (what I thought would be a simple) warmup, I have implemented bubble sort first, using a psuedocode I found online. I had it so the array sorts and changes on screen, but it was too fast so it didn't show the actual animation for the process on how it got to that point. In order to do that I would need to delay each iteration of the loops in the algorithm. However, my implementation is acting strange. The display animates the first iteration being sorted, then suddenly stops. The algorithm seems to quit early instead of finish the whole process when I add setTimeout() to my function. To finish the whole sorting process you need to repeatedly press the button until every single item is sorted. Nothing I try seems to work, and I would be very grateful if anyone could explain why and maybe offer some help.
bubbleSort() {
var arr = this.state.array
var isSorted = false
var lastUnsorted = arr.length - 1
while (!isSorted) {
isSorted = true;
for (let i = 0; i < lastUnsorted; ++i) {
setTimeout(() => {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1)
isSorted = false
}
this.setState({ array: arr })
}, i * 1);
}
lastUnsorted--
}
this.setState({ array: arr })
}
setTimeout is asynchronous, but your code doesn't wait for it to resolve, so it calls setTimeout for lastUnsorted times, so all the timeouts happen at the same time.
You need to controll it with callbacks.
The setup below will cause the console.log('tick') to happen every 1 second for 5 seconds.
const functionToRepeat = () => {
console.log('tick')
}
const loopWithCallback = (callback, i, limit) => {
if(i > limit) return
setTimeout(()=>{
callback(loopWithCallback(callback, i+1, limit))
}, 1000)
}
loopWithCallback(functionToRepeat, 1, 5)

Code is getting stuck somewhere in a succession of for-loops and I'm not sure why

EDIT - I changed the code to correctly declare variables below but nothing seems to have changed
I've written code using a for-loop that has to satisfy a number of criteria before executing what's within it. The problem is that, somewhere along the way, the code is getting stuck inside one of the loops, causing the computer to crash.
I've tried breaking the loop but this doesn't seem to help.
function compareKeypoints(varifiedKeypoints) {
outer_loop: for (i = 0; i < varifiedKeypoints.length; i++) {
let initialKeypoint = varifiedKeypoints[i];
for (j = 0; j < varifiedKeypoints.length; j++) {
let comparisonKeypoint = varifiedKeypoints[j];
if (initialKeypoint.part != comparisonKeypoint.part) {
if (Math.abs(comparisonKeypoint.position.x - initialKeypoint.position.x) <= 20
&& Math.abs(comparisonKeypoint.position.y - initialKeypoint.position.y) <= 20) {
if (keypointsCompatible(initialKeypoint.part, comparisonKeypoint.part)) {
console.log("Activating part: " + initialKeypoint.part);
console.log("Activated part: " + comparisonKeypoint.part);
let keypointPair = {
point_1: initialKeypoint.part,
point_2: comparisonKeypoint.part
}
console.log("Pushing parts!");
activeParts.push(keypointPair);
console.log("breaking loop!");
break outer_loop;
console.log("Loop NOT broken!!");
}
}
}
}
}
if (activeParts.length > 0) {
console.log(activeParts);
}
}
function keypointsCompatible(keypoint_1, keypoint_2) {
var outcome = true;
if (activeParts.length > 0) {
compatibility_loop: for (i = 0; i < activeParts.length; i++) {
if (Object.values(activeParts[i]).includes(keypoint_1) && Object.values(activeParts[i]).includes(keypoint_2)) {
console.log(keypoint_1 + " and " + keypoint_2 + " are not compatible because they already exist as " + activeParts[i].point_1 + " and " + activeParts[i].point_2 + " respectively");
outcome = false;
break compatibility_loop;
console.log("Compatibility NOT broken!!");
}
}
}
console.log("Compatibility outcome is " + outcome);
return outcome;
}
The code is suppose to take two values in the same array and compare them. If a number of conditions are met, including if they're a certain distance apart from one another, they will be pushed into a secondary array. If the values already appear in the secondary array, which the keypointCompatible function is suppose to determine, the loop should either continue looking for other candidates or stop before being called again. For some reason, however, the code is getting stuck within the keypointCompatible function when it detects that the values have already appeared in the secondary array and the console will repeatedly print "Compatibility is false" until the browser crashes.
Working Solution
Use let or const instead of var or nothing. Your issue may be related to closures and variables reused between loops. Make sure you use let or const in your loops too. for (let i=0).
When you use let or const, the runtime will create a new instance every time the block or loop iterates. However, using var will reuse the internal allocation.
So what happens with the standard var is the multiple closures or loops each use the same instance of the variable.
Unless you want the var behavior, always use let or const.
Another Solution
Put a newline after the label compatibility_loop
Still Another Solution
The first function is pushing into activeParts. The second function is looping activeParts. This can go on forever, or longer than expected. Pushing into the array could possibly make the loop limit never reached.
Put a log on the length of activeParts in the second function to see if it is growing out of control.
Your code should be OK if varifiedKeypoints.length has reasonable value. And all internal variables are declared properly!
You have two loops (this inner can start at j=i+1 to save time and multiple calculations) with few conditions inside.
function compareKeypoints(varifiedKeypoints) {
outer_loop: for (let i = 0; i < varifiedKeypoints.length; i++) {
let initialKeypoint = varifiedKeypoints[i];
for (let j = i+1; j < varifiedKeypoints.length; j++) {
let comparisonKeypoint = varifiedKeypoints[j];

Simple arithmetic challenge function with limited attempts

Recently began studying Javascript, trying to read out of Javascript: The Definitive Guide and Eloquent Javascript, while going off on my own to experiment with things in order to really etch them in my memory. I thought a good way to get my head around arithmetic operations and conditional statements, I'd build a series of little games based around each Math operator, and began with addition.
function beginAdditionChallenge() {
var x = Math.ceiling(Math.random()*100);
alert(x);
for (var i = 0; i < 3; i++) {
var a = Number(prompt("Provide the first addend.", ""));
var b = Number(prompt("Provide the second addend.", ""));
if (a + b === x) {
alert("Well done!");
break;
}
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
else {
alert("Fail.");
}
}
}
function initChallenge() {
var button = document.getElementById("challengeButton");
button.addEventListener("click", beginAdditionChallenge);
}
window.addEventListener("load", initChallenge);
You can see the whole thing thus far on JSFiddle, here. The idea is that clicking the button generates a random number between 1 and 100, displays it to the user, then prompts them to provide two addends, giving them 3 attempts. If the sum of these addends is equal to the RNG number, it congratulates the user and ends the program. If they do not provide suitable addends, the loop prompts them to try again, until they've hit 3 attempts, at which point the program snarks at them and ends.
I know the event listener is not the failure point here, as when I change beginAdditionChallenge to simply display a test alert, it works, but I don't know what exactly is wrong with the loop I've created.
You did it correctly. However, Math.ceiling isn't a function and should be Math.ceil. In addition, your code (in jsfiddle) should be set to wrap in head. Why? Because right now you call initChallenge when the page loads. However, in your jsfiddle example, the code runs onLoad so the load event never gets called. Essentially, you're adding a load event after the page has loaded.
http://jsfiddle.net/rNn32/
Edit: In addition, you have a for loop that goes up to three. Therefore
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
should be
else if (a + b !== x && i < 2) {
alert("Please try again.");
}
because when i === 2, the user's last chance has ended.
Everything is fine. Just change:-
var x = Math.ceiling(Math.random()*100);
to:-
var x = Math.ceil(Math.random()*100);

Javascript, loops infinitely and freezes

So I'm making a simple physics simulation using HTML5 canvas and javascript. I'm trying to make some realistic collisions, but whenever a collision occurs the code begins to loop infinitely and freezes the page.
I am using Google Chrome 24.0.1312.32 beta-m
When looking at the javascript console the line "console.log("I am colliding with something")" goes crazy and is printed thousands of times per second and completely breaks the page.
I'm not really sure why its' happening and I have no idea what to do. Any help and/or input would really be appreciated.
for (i = 0; i <= 3; i++) {
if (collide(i)) {
console.log("I am colliding with something");
if (typeof getCollideIndx === 'undefined') {
console.log("collide index is not undefined");
if (!getCollideIndx(i)) {
console.log("Made it past null check");
//...update object based on collision
the collide() function is:
function collide(b) {
for (i = 0; i <= 3; i++) {
//Distance between each object
var distance = (Math.sqrt(Math.pow((balls[b].x - balls[i].x), 2) + Math.pow(balls[b].y - balls[i].y, 2)));
if (distance < 32) {
//must be less than 2*radius -- all radii are the same
//makes it so that it doesn't return true when checking its own index
if (!(balls[b].mass == balls[i].mass)) {
return true;
} else {
return false;
}
}
}
}
I cannot see an infinite loop in your code , my best guess would be this statement
if (typeof getCollideIndx === 'undefined')
fails every time and whatever function the below code is in is called continuously
for (i = 0; i <= 3; i++) {
if (collide(i)) {
console.log("I am colliding with something");
if (typeof getCollideIndx === 'undefined') {
console.log("collide index is not undefined");
if (!getCollideIndx(i)) {
console.log("Made it past null check");
//...update object based on collision
also in this , I do not see the point of the for loop as the control always goes back to the calling function (in the collide() function)
Well, being trapped in that for loop implies that the index variable i is getting set incorrectly somewhere. Without being able to see the entirety of the code I cannot say for sure, but the loop for(i=0; i<3; i++){... will be assigning i to the window object because you have not explicitly scoped it (i.e. for(var i...).
See for example this jsfiddle where the first function will only run once rather than three times because the same variable i is affected in the second function.
Obviously running once != infinite loop, but if the collide function does something to i (or maybe breaks after it finds a collision?) then the value of i will be reset to 0 at the beginning of its for loop each time it's called.
So yeah without some more code I can't say for sure; but my advice in this case is: always use var in for loops or weird things can happen!

Categories

Resources