Question

I'm creating an 'advanced' Tic Tac Toe game in which each turn disappears after 10 seconds (ie: each X or O placed reverts to a blank square after 10 seconds). This all works fine, but the issue arises if a user decides to cancel the current game and start a new one.

If a user starts a new game and clicks on a square that was previously occupied, the timeout function will clear that square in accordance with the click from the previous game -- ie, in less than 10 seconds.

Using clearTimeout resets the timer for the most recent instance of SetTimeout, but doesn't help if there were multiple squares selected when the user reset the game board. And because setTimeout is applied to each X and O in an onclick function, I don't have a way to track multiple instance IDs.

Any thoughts would be much appreciated, code below.

EDIT: You can see a live version of the game (WIP) here: http://kylechadha.com/projects/tic-tac-toe/

Global variables:

var elements = document.getElementsByClassName('cell');
var rows = document.getElementsByClassName('row');
var alternate = 0;
var counter = 0;
var timerX; // Handles setTimeout instances for 'X'
var timerO; // Handles setTimeout instances for 'O'

Function to set X's and O's:

  var play = function() {
  for (i = 0; i < elements.length; i++) {
    elements[i].onclick = function () {
      if (this.className[0] == "c" && win == false) {
        if (alternate % 2 == 0) {
          this.className = "xmove";
          alternate++;
          counter++;
          var paramPass = this;
          timerX = setTimeout(function() {disappear(paramPass);}, 10000) // Handles ID of most recent instance of setTimeout for 'X'
        } else {
          this.className = "omove";
          alternate++;
          counter++;
          var paramPass = this;
          timerO = setTimeout(function() {disappear(paramPass);}, 10000) // Handles ID of most recent instance of setTimeout for 'O'
        }
      }
      position(this);
      analysis();
    }
  }
}

Reset function when user clicks 'New Game':

var reset = function() {
  header[0].innerHTML = "Tic Tac Toe";
  for (i = 0; i < rows.length; i++) {
    for (j = 1; j < 6; j += 2) {
      rows[i].childNodes[j].className = "cell animated bounceIn";
    }
  }
  clearTimeout(timerX); // Clears Timeout for most recent instance (last 'X' clicked) before the game was reset
  clearTimeout(timerO); // Clears Timeout for most recent instance (last 'O' clicked) before the game was reset
  board = [["","",""],["","",""],["","",""]];
  counter = 0;
  alternate = 0;
  win = false;
}
Was it helpful?

Solution

Keep a list of pending timeouts. Each timeout removes itself from the list when it triggers. When you reset, iterate over the list and clearTimeout on each.

Something like this:

var pending = {};
function mySetTimeout(callback, delay) {
  var t;
  t = setTimeout(function() {delete pending[t];callback()}, delay)
  pending[t]=1;
}
function clearAllTimeouts() {
  for (var t in pending) if (pending.hasOwnProperty(t)) {
    clearTimeout(t);
    delete pending[t];
  }
}

OTHER TIPS

The easiest solution would be to create an array of timer IDs and then whenever you want to clear them, iterate through the array with a for loop and use clearTimeout on each. You can use Array.push to add IDs to the timer array.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top