How to Create Tic-Tac-Toe in Your HTML5 Game - dummies

How to Create Tic-Tac-Toe in Your HTML5 Game

By Andy Harris

This game seems like a pretty simple addition to your HTML5 game, but it can be surprisingly difficult to implement well. There are three main aspects to tic-tac-toe that you will need: the visual and data interface, determining a winner and building an AI.


Create the game board

The best way to manage the user interface is to build a simplistic tile-based mechanism. The key to the tic-tac-toe game is a special sprite called a cell. Each cell represents a space on the board. It has three states (X, O, and blank). Clicking on the cell changes the internal state and (of course) the visual representation of the state.

The cell object is simply a subclass of the sprite:

function Cell(){
 tCell = new Sprite(game, "blank.png", 100, 100);
 tCell.state = BLANK;
 tCell.images = new Array("blank.png", "X.png", "O.png");
 tCell.checkClick = function(){
  if (this.isClicked()){
   if (this.state == BLANK){
    this.state = currentPlayer;
    //change the player
    if (currentPlayer == X){
     currentPlayer = O;
    } else {
     currentPlayer = X;
    } // end if
   } // end if
  } // end if
 } // end checkClick
 return tCell;
} // end cell

Here’s how the cell code works:

  1. Create a currentPlayer variable.

    This variable holds the value corresponding to the current player. The current player variable will rotate between X and O.

  2. Assign constants for the states.

    The three states are integer constants.

  3. Create an array of images.

    Assign images that correspond to the various states.

  4. Create a checkClick() method.

    This method will change the cell’s state appropriately. It will also change the currentPlayer variable so the next click will register for the other player.

  5. Build an array of cells.

    Once a single cell does what you want, you can build an array of them.

How to set up the visual layout

The placement of the cells on the screen is interesting. It may seem natural to use a two-dimension array for the tic-tac-toe board, but the nested loop structure can be cumbersome on such a small data structure, and treating the board as a 2D array doesn’t provide many benefits. Instead, consider building this as a single-dimension array.

The cells are arranged like this:

0 1 2
3 4 5
6 7 8

Try dividing all the values in the image above by 3. You’ll see some interesting patterns. Every value in the first row (0, 1, and 2) yield zero (and some remainder) when divided by 3. Each element in the second row (3, 4, and 5) gives 1 remainder something, and each element of the third row produces a 2 remainder something.

If you divide any of these numbers by 3 and convert the result into an integer, you’ll get the row number. In JavaScript, you can use this line of code:

row = parseInt(i / 3);

There’s another interesting pattern if you look at the remainders. All of the numbers in the first column (0, 3, and 6) are evenly divisible by 3, meaning they have remainders of 0. All the numbers in the next column (1, 4, and 7) have a remainder of 1, and the last column produces a remainder of 2. The remainder of division by 3 will give the column number.

In JavaScript, the modulus operator (%) will produce the remainder of an integer division, so you can get the column number with a similar formula:

col = i % 3

The code for creating the cells uses these formulas to extract the row and column number for each cell, and then places the cell on the screen by multiplying these values by the cell width and adding an offset.

 function buildCells(){
  cells = new Array(9);
  xOffset = 100;
  yOffset = 100;
  for (i = 0; i < cells.length; i++){
   cells[i] = new Cell();
   row = parseInt(i / 3);
   col = i % 3;
   xPos = (col * 100) + xOffset;
   yPos = (row * 100) + yOffset;
   cells[i].setPosition(xPos, yPos);
  } // end for loop
 } // end buildCells

How to check your game for a winning combination

The computer doesn’t understand the concept of three in a row, and it needs to be taught.

Take a look at the following code fragment:

  winningCombos = new Array(
   new Array(0, 1, 2),
   new Array(3, 4, 5),
   new Array(6, 7, 8),
   new Array(0, 3, 6),
   new Array(1, 4, 7),
   new Array(2, 5, 8),
   new Array(0, 4, 8),
   new Array(2, 4, 6)

The code simply sets up a two-dimension array. This array is a list of all the winning combinations. If the same player controls cells 0, 1, and 2, that player has won the game. Each row represents a different winning combination.

It then becomes easy to check for a winner:

 function checkWins(){
  winner = 0
  for (combo = 0; combo < winningCombos.length; combo++){
   a = winningCombos[combo][0];
   b = winningCombos[combo][1];
   c = winningCombos[combo][2];
   if (cells[a].state == cells[b].state){
    if (cells[b].state == cells[c].state){
     if (cells[a].state != BLANK){
      winner = cells[a].state;
     } // end if
    } // end if
   } // end if
  } // end for
  return winner;
 } // end checkWins

How to add an AI

The most common type of artificial intelligence for this sort of problem is called a heuristic algorithm. It’s a trick that allows the computer to quickly come up with a good solution while not guaranteeing a perfect solution.

The general strategy is to build an array of cell rankings:

  cellRank = new Array(3,2,3,3,4,3,3,2,3);

The rank of each cell indicates the number of winning combinations that go through it, so cell 4 (the center cell) is the most valuable cell at the beginning of the game.

As the game goes on, the computer reevaluates the grid according to the following simplistic calculations:

  1. If any cell is nonblank, demote it.

    The only cells you should consider are those that are blank, so if a cell is already taken, subtract 99 from its cell ranking.

  2. Look for partially completed winning combinations.

    Step through each winning combination. If any two cells have the same value but the third is blank, add a value to the third.

  3. Find the highest cell.

    After going through all the combinations, loop through the cell rankings to see which is the highest cell ranking.