0

Please look at this codepen: http://codepen.io/dragonOne/pen/rrwrQw (doesn't work yet!)

I want this Javascript memory board to display cards one by one in spiral order.

The spiralOrder(output) function takes in a matrix of div id's and changes each card div (id is tile_i) to display = "block" one by one in spiral order, every two seconds. But my setTimeout isn't working properly and is only displaying the first four cards (all at once...)

When I read the console.log in spiralOrder I see that the function correctly reads each card in the order that I want. But how come my setTimeout isn't working to add delay after every card display?

function spiralOrder(output) {

  // Initialize our four indexes
  var top = 0;
  var down = output.length - 1;
  var left = 0;
  var right = output[0].length - 1;
  var regexp = /\d+/g;

  while(true)
  {
    // Starting showing top row
    for(var j = left; j <= right; ++j) {
      console.log("tile_"+output[top][j].match(regexp)); //THIS SHOWS SPIRAL ALGORITHM IS CORRECT
      setTimeout(function() { document.getElementById("tile_"+output[top][j].match(regexp)).style.display = "block"; }, 2000); //THIS DOESN'T BEHAVE RIGHT
    }
    top++;
    if(top > down || left > right) { 
      break;
    }
    //Starting showing rightmost column 
    for(var i = top; i <= down; ++i){
      console.log("tile_"+output[i][right].match(regexp));
      setTimeout(function() { document.getElementById("tile_"+output[i][right].match(regexp)).style.display = "block"; }, 2000);
    }
    right--;
    if(top > down || left > right) { 
      break;
    }
    //Starting showing bottom row 
    for(var j = right; j >= left; --j){
      console.log("tile_"+output[down][j].match(regexp));
      setTimeout(function() { document.getElementById("tile_"+output[down][j].match(regexp)).style.display = "block"; }, 2000);
    }
    down--;
    if(top > down || left > right) { 
      break;
    }
    //Starting showing leftmost column 
    for(var i = down; i >= top; --i){
      console.log("tile_"+output[i][left].match(regexp));
      setTimeout(function() { document.getElementById("tile_"+output[i][left].match(regexp)).style.display = "block"; }, 2000);
    }
    left++;
    if(top > down || left > right) { 
      break;
    }
  }
}

What is going wrong here?

RJK
  • 226
  • 1
  • 6
  • 22
  • `setTimeout()` is not blocking. It just schedules something to run at some time in the future and then the rest of your code keeps running. So, you just end up scheduling a whole bunch of `setTimeout()`s for about the same time. – jfriend00 Sep 28 '16 at 05:33
  • Possible duplicate of [How do I add a delay in a JavaScript loop?](http://stackoverflow.com/questions/3583724/how-do-i-add-a-delay-in-a-javascript-loop) – DrC Sep 28 '16 at 05:38

1 Answers1

0

You are trying to use setTimeout as a pause function. That isn't what it does. It just ensures that the contained function is called around the offset time. So, in your code, it is running through all of the divs and scheduling all the calls to occur simultaneously in about 2 seconds.

Couple of possible solutions

  • (POOR) Rewrite the code to call the timeout functions at (count++)*2000 so they are called successively
  • (BETTER) Rewrite the code so that the timeout function updates one div and then updates state and sets another timeout to perform the next update (and so on). Basically unwrap your loops into a series of timeout callbacks.

Update: take a look at How do I add a delay in a JavaScript loop?

Community
  • 1
  • 1
DrC
  • 7,528
  • 1
  • 22
  • 37
  • Could you expand on what you meant for the 1st suggestion? `setTimeout(function() { document.getElementById("tile_"+output[down][j].match(regexp)).style.display = "block"; }, 2000);`, change the `2000`? – RJK Sep 28 '16 at 05:38
  • Schedule the callbacks so the first is at 2s the next at 4s, then 6s, 8s, 10s, .... So set `count=1` at the top and then `setTimeout(..., (count++)*2000);` – DrC Sep 28 '16 at 05:39
  • Have to be honest. I'm struggling to figure out how I will change my iterative for loops to recursion (as stated in your link). Could you point me to the right direction? – RJK Sep 28 '16 at 05:41
  • It isn't trivial. Look at the linked question and rewrite each of your loops as a single callback function in that model. Next have the first callback invoke the second when it has run through its range. And so on. – DrC Sep 28 '16 at 05:44