Creating a tic-tac-toe game with jQuery – Part 1

As promised, our first tutorial will be for programming a very well-known game called tic-tac-toe. We will start our tutorials with a general design requirements section and since I’m pretty sure you all know this game it’s going to be a very short one for now.
So what do we need from our game?

  1. The size of the game map is 3×3.
  2. We have 2 players (X & O).
  3. Each player makes a single move in his turn.
  4. A move means marking a field in the map with the player’s mark.
  5. A player wins when he has a full row / column / diagonal.

Now that we have our basic design requirements, we can start programming them one by one. I’m going to assume you already know how to create the needed html/js/css files and connect them. You will also need to connect your html file to jQuery, since we are going to rely on it.

For those of you who might still be having problems with creating the structure of the files together there is a demo available at the end of this post. Feel free to take a peek there.

1. The size of the game map is 3×3

To create the game map we can just create 9 divs in our html file, but instead of that I’d like to create them with the help of a little JavaScript, since this is one of the requirements that look like something we might want to expand later on.
In order to do this, let’s start by creating a div to be our game map.

<div id="game_map"></div>

CSS:

#game_map{
    border: 1px solid #000;
    clear: both;
    float: left;
}

and now let’s populate that div with some JavaScript:

// We start by emptying the div so that it will only contain
// what we put in it ourselves
$("#game_map").empty();
// Then for every column and row, we will...
for(var i=0; i<num_of_cols*num_of_rows;++i)
{
    // create a div to be a cell in the game map, and...
    var cell = $("<div></div>")
            .addClass("cell")
            .appendTo("#game_map");
    // add the line breaks to handle the rows
    // in a quite cross-browser way
    if ( i % num_of_cols === 0 ){
        cell.before('<div class="clear"></div>');
    }
}

CSS:

#game_map .cell{
    cursor: pointer;
    float: left;
    border: 1px solid #000;
    width: 60px;
    height: 60px;
    line-height: 60px;
    font-size: 30px;
    text-align: center;
}
.clear{
    clear: both;
    line-height: 0px;
}

So, we’ve created a floating div to act as our game map. For every row and col(umn), we’ve attached a small floating div to act as a cell in our game map. There are various ways to position the cell in the game map, but I don’t want to position them; I think its simple and fun to just float them. But since floating everything has its own small price, we’ve also added a small non-symantic div to the game map to handle our rows.

There are many hacks and tricks to avoid adding markup for layout, but I consider this little extra markup to be quite harmless.

2. We have 2 players (X & O)

The number of players and their marks is another item that looks like we can customize it later on. So we might leave some places ready for customization, without really delving into the little details.

So what does having 2 players mean? For one thing, it means we will need to keep track of the score ๐Ÿ™‚ . It also means that we might need to indicate who is playing and who’s won. We will also need to have some kind of representation for the players and their respective marks (X / O).

So let’s see how we can achieve those goals. Let’s start by representing our players:

// The first player
var player1 = {
    mark: 'X',
    name: 'Player 1',
    style: 'player1_cell',
    score_el: 'player1_wins',
    wins: 0};
// The second player
var player2 = {
    mark: 'O',
    name: 'Player 2',
    style: 'player2_cell',
    score_el: 'player2_wins',
    wins: 0
};
var players = [player1, player2];
var current_player = 0;

What we just did was define two simple objects with the following attributes: mark (e.g., X, O), name, style (which will direct to the css class the player uses) and score_el (score_el holds the element id for the element which we want to update with the player’s score). After that, we put the players in an array in order to be able to access them easily with an index: current_player.

So far it’s pretty simple, and soon we will see how we can use all of the objects which we’ve just defined.

Before we go on, let’s define the css classes that will be used to represent the players in the game: player1_cell & player2_cell.

#game_map .player1_cell{
    color: #cc0000;
}
#game_map .player2_cell{
    color: #0000cc;
}

As you can clearly see, these classes are just used to make the display a bit clearer, and distinguish between players.

3. Each player makes a single move in his turn

Some games allow the players to play simultaneously, but in tic-tac-toe the players take turns playing, which makes things simpler for us ๐Ÿ™‚ .
So what do turns mean? Mostly they mean that it’s time to indicate who’s supposed to be playing now.
Let’s prepare some html elements for the display:

<span id="player_name"></span>make your move (<span id="player_mark"></span>)

We’ve added a simple line with placeholders for the player’s name and his mark. Now let’s fill them with some JavaScript code:

function initTurn(){
    $("#player_name").text(players[current_player].name);
    $("#player_mark").text(players[current_player].mark);
};

Now we’ve added the function that will be called to initialize the values in the html placeholders.

4. A move means marking a field in the map with the playerโ€™s mark

So far so good. We now know who’s turn is it, but we still haven’t addressed what the player can do in his turn and what a move really does. So what does a move mean? It means that the player will do something in his turn: he will move the mouse and click a cell in the game map. These actions will result in his mark being placed in the chosen cell and so on… let’s see how we can achieve all of this.
Look at the following code:

$("#game_map .cell")
    .bind("click", playMove)
    .bind('mouseover', hoverCell)
    .bind('mouseout', leaveCell);

What we did here was define some events. This code will be placed with the same code we used earlier to create the game map. I chose to use the jQuery .bind method instead of the .click since we need to use the great power of .unbind later on; an event attached with .bind can be detached very easily using .unbind.

So now that we have the events set up for us let’s move on to the functions we attached:

function hoverCell(ev){
    $(this).addClass("hover");
    return false;
};
function leaveCell(ev){
    $(this).removeClass("hover");
    return false;
};
function playMove(ev){
    var cell = $(this);
    cell
        .addClass(players[current_player].style)
        .addClass("marked")
        .text(players[current_player].mark)
        .trigger("mouseout")
        .unbind("click mouseover mouseout");
   
    // Check if someone won
    if ( !checkAndProcessWin() ) {
        // Change the current player
        current_player = (++current_player) % players.length;
        initTurn(current_player);
    }
    return false;
};

The first two functions are quite simple, when the mouse enters a certain field we attach a hover class, and when the mouse leaves the field we remove the class. If you are wondering why we haven’t used the :hover pesudo css class, it’s because it will not work in older browsers like IE6 and it’s simpler to turn off a bind function than to replace css classes and play with what comes first. Using the JavaScript method, we have a simple .hover jQuery method, but again we need the power of unbind.

The playMove function adds the player’s style and mark to the clicked element and then disables it by removing the events from it, but not before it triggers the mouseout event so we will not stay with the hover class. After making these changes to the element itself (the cell on which the player clicked), the function also calls the checkAndProcessWin() function, which will check what happened after the player made his move and act accordingly.

We then change the current player by rotating the players, as follows: if the current index is 0 it means we’re using the first element in our players array which is player1. Increasing it by one will make us use player2. After that we want to go back to the first index, which is why we’re using the % operator with the numbers of players. As you will soon see in the function that checks the win condition, the % operator is about to become our best friend.

5. A player wins when he has a full row / column / diagonal

The last (but not least) requirement in our game design. Most of the core of our game is here, where we check the winning condition and what to do with it.

This function is a bit more complicated than the ones we’ve had so far, but I’ve tried to keep it simple as I could make it. We will add a new custom selector in our document ready function as follows:

$.expr[":"].mod = function(el, i, m) {
    return i % m[3] === 0
};  
$.expr[":"].sub_mod = function(el, i, m) {
    var params = m[3].split(",");
    return (i-params[0]) % params[1] === 0
};

Custom selectors are one of jQuery’s strong sides. You will see how we’ll use these selectors in our win condition function in just a bit.

So how are we going to check if the player’s won? Let’s think of our game map / board for a bit: A player wins the game if he manages to fill any row, column or diagonal, so we need to check if the current player did so. Let’s start by checking the rows:

for (var row=1; row <= num_of_rows && !win; ++row )
{
    cells_inspected = cells
        .filter(":lt("+num_of_cols*row+")")
        .filter(":eq("+(num_of_cols*(row-1))+"),:gt("+(num_of_cols*(row-1))+")")
        .filter("."+current_class);
    if ( cells_inspected.length == num_of_cols ) win = true;
}

To check the rows, we’ve created a for loop to go over each row until it either scans all the rows or finds a win condition. For each row the function filters out the cells of the game map that don’t belong to that row, leaving us with only the row’s cells. Then the function filters out any cells that don’t belong to the current player. This leaves us with all the cells owned by the current player in the current row. If the function finds that the player owns all the cells in the row, it returns a win.

Now let’s check the columns. We’ve already added a custom selector so it’s time to see it in action.

for (var col=0; col <= num_of_cols && !win; ++col )
{
    cells_inspected = cells
        .filter(":sub_mod("+col+","+num_of_rows+")")
        .filter("."+current_class);
    if ( cells_inspected.length == num_of_rows ) win = true;
}

See how easy it is to check the columns when we have our custom selectors? All we need to do is to filter the column according to a certain modulus and see if we have a match. Most of the logic here is the same as when we checked the rows, but here we have the help of our custom selector named :sub_mod.

OK, we’ve checked the rows and the columns, but we still have the diagonals to check. For this task we don’t need loops, since we will always have exactly 2 diagonals, regardless of the game map size.

cells_inspected = cells
    .filter(":mod("+(num_of_rows+1)+")")
    .filter("."+current_class);
if ( cells_inspected.length == num_of_rows ) win = true;
else{
    // From lower right to upper left
    cells_inspected = cells
        .filter(":mod("+(num_of_rows-1)+"):not(:last,:first)")
        .filter("."+current_class);
    if ( cells_inspected.length == num_of_rows ) win = true;
}

Both diagonals are checked with the help of the modulus functionality, though we don’t use it in quite the same way. We also need to take care not to select the fields (last and first) in the last check since they can never be part of the win condition there.

Those were all the conditions we needed to check in order to find if the player won. There is a bit more work to be done in this function, like speeding things up a bit (for example, check if we have less than 3 fields marked, since that would mean there is no chance of a win). We also need to notify everyone of the win, maybe with some fireworks… You can see the complete function in the demo files.

Before We Finish

That was quite lot to cover in one go, but we are not done with our little game yet. I’ve left out some of the code in an attempt to keep things as simple as possible, but please feel free to check out the demo to see the rest. Also, since we are talking about web development playing locally is a bit… wrong ๐Ÿ˜‰ . So next we are going to see how we can add some multiplayer support so you can play with your friends online. We will also add some basic AI so you can play against the computer, and see how we can customize the game a bit.

Zip file for this tutorial

Demo for this tutorial

So until next time, have fun

Adi Gabai

6 Responses to Creating a tic-tac-toe game with jQuery – Part 1

  • how can i made same game with large grid ?
    large tic tac toe?
    winner / loser core must change.

  • is there any video to understand this

  • Hey, a quick optimization that would let you get rid of the ‘clear’ class in css:

    #game_map{
    border: 1px solid #000;
    float: left;
    }
    // We start by emptying the div so that it will only contain
    // what we put in it ourselves
    $(“#game_map”).empty();
    var num_of_cols = 3, num_of_rows = 3;
    // Then for every column and row, we will…
    for(var i=0; i<num_of_cols*num_of_rows;++i)
    {
    // create a div to be a cell in the game map, and…
    var cell = $("”)
    .addClass(“cell”)
    .appendTo(“#game_map”);
    // add the line breaks to handle the rows
    // in a quite cross-browser way
    if ( i % num_of_cols === 0 ){
    cell.css(‘clear’, ‘left’);
    }
    }

  • code to generate table using textboxes

    Generate Table

    function generate()
    {
    var x = document.getElementById(“tb1”).value;
    var y = document.getElementById(“tb2”).value;
    var tbl = document.getElementById(“table1”);
    var tblbody = document.createElement(“tablebody”)
    var i,j;
    for(i = 0 ; i < x ; i++)
    {
    var row = document.createElement("tr");
    for (j = 0 ; j < y ; j++)
    {
    var cell = document.createElement("td");
    var celltext = document.createTextNode("cell is row "+j+",column" +i);
    cell.appendChild(celltext);
    row.appendChild(cell);
    }
    tblbody.appendChild(row);
    }
    tbl.appendChild(tblbody);
    body.appendChild(tbl);
    tbl.setAttribute("border","1");
    }

    Row :
    Column :

  • I did not understand the Tic Tac Toe game code.
    Can i have the source file of simple code,which is easy to understand.

Leave a Reply

Your email address will not be published. Required fields are marked *

Categories