Delay in for loop breaks function - javascript

I need to create a small delay in this for loop:
for (i = 1; i <= cloneIndex; i++) {
var myElem = document.getElementById('form' + i);
if (myElem != null) {
function postData() {
return {
udd: document.getElementById('udd').value,
data: date_in,
hora_ini: hour_in,
hora_fim: hour_out,
cat: $('#form' + i).find('select[id="cat"]').val(),
m1: $('#form' + i).find('select[id="q1"]').val(),
m2: $('#form' + i).find('select[id="q2"]').val(),
m3: $('#form' + i).find('select[id="q3"]').val(),
m4: $('#form' + i).find('select[id="q4"]').val(),
m5: $('#form' + i).find('select[id="q5"]').val()
}
}
var newItem = postData();
$2sxc(#Dnn.Module.ModuleID).webApi.post('app/auto/content/audits', {}, newItem);
}
}
Following stackoverflow examples, I tried this solution:
for (i = 1; i <= cloneIndex; i++) {
(function(i){
setTimeout(function(){
var myElem = document.getElementById('form' + i);
if (myElem != null) {
function postData() {
return {
udd: document.getElementById('udd').value,
data: date_in,
hora_ini: hour_in,
hora_fim: hour_out,
cat: $('#form' + i).find('select[id="cat"]').val(),
m1: $('#form' + i).find('select[id="q1"]').val(),
m2: $('#form' + i).find('select[id="q2"]').val(),
m3: $('#form' + i).find('select[id="q3"]').val(),
m4: $('#form' + i).find('select[id="q4"]').val(),
m5: $('#form' + i).find('select[id="q5"]').val()
}
}
var newItem = postData();
$2sxc(Dnn.Module.ModuleID).webApi.post('app/auto/content/audits', {}, newItem);
}
}, 1000 * i);
}(i));
}
However this breaks the function inside. It seems myElem is now always null. Too many "i"s? How can I fix this?

You need to define the variable inside the closure for it to be unique to each iteration:
for (var i = 1; i < 10; i++) {
(function() {
var k = i; // <-- k will be different for each iteration, because it was declared inside the closure. i was defined outside the closure.
setTimeout(function() {
console.log("Delayed: ", i, k)
}, i * 1000)
}());
}
...or else include i in the closure definition:
for (var i = 1; i < 10; i++) {
(function(i) {
setTimeout(function() {
console.log("Delayed: ", i)
}, i * 1000)
}(i));
}

Nevermind. The reason the code did not work was simple. The rest of the code below did not wait for the delayed loop to end, so it actually broke the function.
This fixed it (placed inside the setTimeout function):
k++;
if (k == cloneIndex) {rest of the code that needs the loop to end}

Related

For-loop that is skipping even count

I have a small for loop, but it is skipping even count , what am I missing ?
var i = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + i++);
//code above
if (i < 20) {
myLoop();
}
}, i++)
}
myLoop()
i++ is equal i = i + 1; But when you call console.log(i++), first thing wil be console.log with Old value, and after increment your value.
You raise the timeout with every iteration by on millisecond. Is that what you wanted?
https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout(function, milliseconds, param1, param2, ...)
var i = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + i++);
//code above
if (i < 20) {
myLoop();
}
}, 1)
}
myLoop()
Your i++ in the console.log statement is modifying your i variable.
i++ is equal to i = i + 1.
Replace i++ with i, which will evaluate correctly as postfix increment will return the value before the modification which would just be i.
This works:
var i = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + i);
//code above
if (i < 20) {
myLoop();
}
}, i++)
}
myLoop()
Can also be done by adding another variable for the console.log
var i = 0;
var t = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + t++);
//code above
if (t < 20) {
myLoop();
}
}, i++)
}
myLoop()
You have i++ twice in your code. First you increment it when you call setTimeout at the bottom of your code and then you display the uneven value via console log and increment i. Change your logging to
console.log(Date() + ' and count is ' + i);

function prevents rest of code from working

function updateScreen() {
var textOutput = "";
setScreen("yellowScreen");
for (var i=0; i < finalColor.length; i++){
var newIndex = i+1;
textOutput = (((textOutput + newIndex +". NAME: " +finalName[i] + ", "
+ "scientific name is") + finalScientificName[i] + ", " + "this bird is
")+ finalConservationStatues[i] + "and they eat ")+ finalDiet[i]+"\n\n";
}
setText("yellowOutput", textOutput);
console.log(textOutput);
}
onEvent("yellowButton", "click", function( ) {
yellowFilter();
upDateScreen();
});
the function yellowFilter prevents anything else to run
function yellowFilter() {
for (var i = 0; color.length; i++) {
if (color[i] == 'Yellow' ) {
appendItem(finalColor, color[i]);
appendItem(finalDiet, diet[i]);
appendItem(finalConservationStatues, conservationStatus[i]);
appendItem(finalScientificName, scientificName[i]);
appendItem(finalName, Name[i]);
console.log(finalColor);
}
}
}
is there anything wrong with these functions the update screen function doesn't run if the yellowFilter runs but yellowFilter needs to run so that upDateScreen can run properly
Without actually going through anything I see one error immediately:
for (var i = 0; color.length; i++)
The second statement in a for loop needs to be a conditional

Nested for loop,delay on each loop individually

An example of simple nested for loop:
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
console.log("i is: " + i);
console.log("j is: " + j);
console.log("---");
}
}
Nested for loop with delay:
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
task(i,j);
}
}
function task(i,j) {
setTimeout(function() {
console.log("i is: " + i);
console.log("j is: " + j);
console.log("---")
}, 1000 * i);
}
NOW MY QUESTION IS
How can I delay each loop seperately.
Current output (ignore the "---"):
i, j, delay, i, j, delay, ...
Desired output (ignore the "---"):
i, delay, j, delay, i, delay, j, delay ...
I tried things like below (but its returning a complete wrong output)
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
taski(i);
taskj(j)
}
}
function taski(i) {
setTimeout(function() {
console.log("i is: " + i);
}, 1000 * i);
}
function taskj(j){
setTimeout(function() {
console.log("j is: " + j);
}, 1000 * j);
}
You could use Promise and async/await to handle sequential call
function taski(i) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log("i is: " + i)
resolve()
}, 1000 * i)
})
}
function taskj(j) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log("j is: " + j)
resolve()
}, 1000 * j)
})
}
async function execute() {
for (let i = 0; i <= 2; i++) {
for (let j = 0; j <= 1; j++) {
await taski(i)
console.log("delay")
await taskj(j)
console.log("delay")
}
}
}
execute()
Reference:
async function
Promise
Ok the thing is setTimeout works in it's own world that isn't limited by the for loops, or any other code for that matter, it doesn't actually "block" the current code at all, in the for loop you are just setting up a bunch of intervals, really fast one after the other (since the for loop doesn't stop or get delayed by the timeouts), which later execute in some unknown order when the time for each one individually runs out, which is not blocked or dependant on any of the other timeouts
If you want to keep relatively the same format you have now, but with delay blocking you can use await and promises and async functions
(async () =>
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
await taski(i);
await taskj(j)
}
}
)()
function taski(i) {
return new Promise((rs) => setTimeout(function() {
res(console.log("i is: " + i));
}, 1000 * i));
}
function taskj(j){
return new Promise((rs) => setTimeout(function() {
res(console.log("j is: " + j)
}, 1000 * j));
}
You could try to to an asynchronous approach with async/await:
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
(async function() {
for (let i = 0; i <= 2; i++) {
for (let j = 0; j <= 1; j++) {
await taski(i);
await taskj(j);
}
}
}())
async function taski(i) {
await sleep(1000 * i);
console.log("i is: " + i);
}
async function taskj(j) {
await sleep(1000 * j);
console.log("j is: " + j);
}

How to use recursion in Javascript to find the best possible Texas Hold 'em hand?

I'm trying to come up with a quick way to evaluate a poker hand consisting of the usual five community cards and two cards unique to each player, so seven cards in total.
I read an article about a poker evaluator algorithm that uses recursion to first bring down the number of cards from seven to five, and then calculate the result from that.
I've had to use recursion at college a few times, but I can't see how it is applicable to this situation.
From what I understand, this guy is saying: We calculate the best possible five card result of each seven hand combination, so that'd imply that the whole evaluator logic would be contained within this recursive loop, but I don't see a) how this recursive loop will eventually reach its base case, and b) how to implement this.
Any help would be greatly appreciated!
Source Code
var suits = ['Clubs', 'Spades', 'Hearts', 'Diamonds'];
var ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace'];
var combinations = ['Royal Flush', 'Straight Flush', 'Four of a Kind', 'Full House', 'Flush', 'Straight', 'Three of a Kind', 'Two Pair', 'One Pair'];
var deck = [];
var players = [new Player(), new Player()];
var table = [];
function Player() {
this.hand = [];
this.result;
}
function Card(suit, rank) {
this.suit = suit;
this.rank = rank;
this.name = rank + ' of ' + suit;
}
function initDeck() {
deck = [];
for(var i = 0; i < 4; i++) {
for(var j = 0; j < 13; j++) {
deck.push(new Card(suits[i], ranks[j]));
}
}
}
function drawCard() {
var randNumber = Math.floor(Math.random() * deck.length);
var drawnCard = deck[randNumber];
deck.splice(randNumber, 1);
return drawnCard;
}
function dealCards() {
for(var i = 0; i < 2; i++) {
for(var j = 0; j < players.length; j++) {
var drawnCard = drawCard();
players[j].hand.push(drawnCard);
}
}
}
function flop() {
for(var i = 0; i < 3; i++) {
var drawnCard = drawCard();
table.push(drawnCard);
}
}
function turn() {
var drawnCard = drawCard();
table.push(drawnCard);
}
function river() {
var drawnCard = drawCard();
table.push(drawnCard);
}
function showDown() {
for(var i = 0; i < players.length; i++) {
evaluate(i);
document.write("<br>");
}
}
function evaluate(player) {
var totalHand = players[player].hand.concat(table);
}
initDeck();
dealCards();
document.write("Player 1: " + players[0].hand[0].name + ' and ' + players[0].hand[1].name + '<br>');
document.write("Player 2: " + players[1].hand[0].name + ' and ' + players[1].hand[1].name + '<br><br>');
flop();
document.write("Flop: " + table[0].name + ', ' + table[1].name + ' and ' + table[2].name + '<br>');
turn();
document.write("Turn: " + table[0].name + ', ' + table[1].name + ', ' + table[2].name + ' and ' + table[3].name + '<br>');
river();
document.write("River: " + table[0].name + ', ' + table[1].name + ', ' + table[2].name + ', ' + table[3].name + ' and ' + table[4].name + '<br>');
showDown();
I don't know about recursion, but you can brute force it with for loops:
var suits = ['Clubs', 'Spades', 'Hearts', 'Diamonds'];
var ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace'];
var deck = [];
var allSets = [];
var combinations = [{
name: 'Straight flush',
test: function(cards) {
//All must have same suit
if (cards.some(function(card) {
return card.suit != cards[0].suit;
})) {
return false;
}
//Is consecutive
var arr = cards
.map(function(card) {
return card.rank;
})
.sort(function(a, b) {
return a - b;
});
return Math.abs(arr[0] - arr[arr.length - 1]) <= 4;
},
success: function() {
//return a score modifier
return 100;
}
}];
//Card class
var Card = (function() {
function Card(suit, rank) {
this.suit = suit;
this.rank = rank;
this.id = Card._id++;
}
return Card;
}());
Card._id = 0;
//Build deck
for (var suit = 0; suit < suits.length; suit++) {
for (var rank = 0; rank < ranks.length; rank++) {
deck.push(new Card(suit, rank));
}
}
//Find sets
for (var index0 = 0; index0 < deck.length; index0++) {
for (var index1 = index0 + 1; index1 < deck.length; index1++) {
for (var index2 = index1 + 1; index2 < deck.length; index2++) {
for (var index3 = index2 + 1; index3 < deck.length; index3++) {
for (var index4 = index3 + 1; index4 < deck.length; index4++) {
var set = [deck[index0], deck[index1], deck[index2], deck[index3], deck[index4]];
var score = 0;
for (var index = 0; index < set.length; index++) {
score += set[index].rank;
}
for (var combinationIndex = 0; combinationIndex < combinations.length; combinationIndex++) {
var combination = combinations[combinationIndex];
if (combination.test(set)) {
score += combination.success();
break;
}
}
allSets.push({
set: set.slice(0),
score: score
});
}
}
}
}
}
//Sort sets
allSets = allSets
.sort(function(a, b) {
return b.score - a.score;
});
//Display 100 best sets
console.log("100 best:", allSets
.slice(0, 100).map(function(a) {
a.set = a.set
.map(function(b) {
return suits[b.suit] + "" + ranks[b.rank];
})
.join(", ");
return a;
}));
Just extends the combinations list with any test you wish to run.

jquery dynamic content and date output

var jsonObj = jQuery.parseJSON(passData);
thisId = jsonObj.id;
thisPage = jsonObj.page;
thisPageItem = jsonObj.item;
if (jsonObj.json != undefined) {
$.each(jsonObj.json, function (key, tempJson) {
if (tempJson.position != undefined) {
var tempId = tempJson.id;
var tempStyle = tempJson.position;
objJsonArr[tempId] = tempStyle;
}
});
}
for (var i = 1; i < 9; i++) {
var tempList = window.objJsonArr;
var tempDom = '#dropAbleArea #area.' + i;
$(tempDom).css('top', dropObjectPositionArr[i].top);
$(tempDom).css('left', dropObjectPositionArr[i].left);
console.log("Out " + objJsonArr[i]);
$(tempDom).load('images/pageThree/' + i + '.svg', null, function (e) {
console.log("In " + objJsonArr[i]);
});
}
$.each(objJsonArr, function (key, value) {
if (value != undefined) {
$('#dropAbleArea div#area').on('', function (e) {
$('#dropAbleArea div#area.' + key + ' g#ball path#bk').attr('style', value);
});
};
});
the return is
[Log] Out fill:rgb(244, 133, 142) (3.html, line 130)
[Log] Out fill:rgb(130, 202, 156) (3.html, line 130)
[Log] Out fill:rgb(207, 229, 174) (3.html, line 130)
[Log] Out fill:rgb(130, 202, 156) (3.html, line 130)
[Log] Out undefined (3.html, line 130, x4)
[Log] In undefined (3.html, line 132, x8)
Q1: I can't get the javascript array data in the console.log("In " + objJsonArr[i]);
Q2: How can i get the dynamic content in the
$('#dropAbleArea div#area').on('',function(e){
$('#dropAbleArea div#area.' + key +' g#ball path#bk').attr('style',value);
});
The complete function given to jQuery .load captures the variables objJsonArr and i. But when the function is executed, the loop has already finished and i has the value 9 and objJsonArr[9] seems to be undefined.
You can see the same effect with a delayed function
var a = [ 1, 2, 3 ];
for (var i = 0; i < a.length; ++i) {
setTimeout(function() {
console.log('a[' + i + ']=' + a[i]);
}, 500);
}
which gives the output
a[3]=undefined
JSFiddle
You can "fix" this with creating an additional scope by wrapping the anonymous function, where you capture the loop variable's value in a another variable k
var a = [ 1, 2, 3 ];
for (var i = 0; i < a.length; ++i) {
setTimeout((function(k, v) {
return function() {
console.log('a[' + k + ']=' + v);
};
})(i, a[i]), 500);
}
JSFiddle
In your case, this would be something like
$(tempDom).load('images/pageThree/' + i + '.svg', null, (function(v) {
return function (e) {
console.log("In " + v);
};
})(objJsonArr[i]));
Update:
I just learned about jQuery.proxy() and it seems to be the solution to your problem. Taking my first example and applying jQuery.proxy to it will give
var a = [ 1, 2, 3 ];
for (var i = 0; i < a.length; ++i) {
setTimeout($.proxy(function(k, v) {
console.log('a[' + k + ']=' + v);
}, null, i, a[i]), 500);
}
JSFiddle
This is equivalent to the closure in my second example, where the two values are captured. Equally, using $.proxy in your program will be
$(tempDom).load('images/pageThree/' + i + '.svg', null, $.proxy(function (v, e) {
console.log("In " + v);
}, null, objJsonArr[i]));

Categories

Resources