0

I'm working on a Simon Says program and I am running into issues with calling the computer's series of moves and displaying them on the screen.

I am attempting to use this aiMoves() function to iterate through the array and display each move by highlighting the appropriate color button. I am attempting to use setInterval so that the first button highlights, the program waits a second, then the next button highlights like so:

function aiTurns(randNum){
  for(var i = 0; i < aiMoves.length; i++) {
    if(aiMoves[i] === 1){
      //sound1();
      $('#green').addClass("active");
      setTimeout(function(){
        $('#green').removeClass("active");
      }, 500);
    }
    else if(aiMoves[i] === 2){
      //sound2();
      $('#red').addClass("active");
      setTimeout(function(){
        $('#red').removeClass("active");
      }, 500);
    }
    else if(aiMoves[i] === 3) {
      //sound3();
      $('#yellow').addClass("active");
      setTimeout(function(){
         $('#yellow').removeClass("active");
        }, 500);
      }
      else if(aiMoves[i] === 4){
      //sound4();
      $('#blue').addClass("active");
      setTimeout(function(){
        $('#blue').removeClass("active");
      }, 500);
    }
    level--;
    playerTurn = true;
  }

}

I called it like this:

var moves = function() {
aiTurns(randomNumber());

}

setInterval(moves, 2000);
} 

The problem is setInterval is asynchronous and all iterations of the for loop within aiMoves() are called at the same time. How can I set this up so that the first element of the array executes, it pauses, then the next elements executes?

Here is the codepen for a better visualization: https://codepen.io/nick_kinlen/pen/oGjMMr?editors=0010

2 Answers 2

2

Since the for loop runs immediately until completion, you'll need a different way to run async code in series. Here's a simple abstraction that lets you loop over an array with a given delay in between each iteration:

function intervalForEach (array, iteratee, delay) {
  let current = 0

  let interval = setInterval(() => {
    if (current === array.length) {
      clearInterval(interval)
    } else {
      iteratee(array[current])
      current++
    }
  }, delay)
}

All of your conditional logic can go inside of the iteratee function, which just accepts the current item in the array. Here's a working example.

Sign up to request clarification or add additional context in comments.

Comments

0

Here's a different way to do it with async/await:

const timeout = ms => new Promise(res => setTimeout(res, ms));

(async () => {
  var i = 1;
  while (true) {
    await timeout(1000);
    // iteration logic
    console.log(i++);
    // termination logic
    if(i > 10) {
      break;
    }
  }
  console.log("done");
})();

Here set interval is completely replaced with a Promise using setTimeout, an await, and a while loop.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.