SECRET OF CSS

Create a Tic-Tac-Toe with HTML and JavaScript | by Nicolai B. Andersen | Jul, 2022


Learn to implement the game on your website

Photo by Pixabay: https://www.pexels.com/da-dk/foto/farve-form-hjerte-kamp-220057/
Photo by Pixabay: https://www.pexels.com/da-dk/foto/farve-form-hjerte-kamp-220057/

Tic-tac-toe, noughts and crosses, or as we call it in danish “kryds og bolle”. It may seem like one of the most simple games to recreate, but it includes some valuable problems which are great for beginners. This article explains how to create the game with an HTML Canvas element and JavaScript.

A GIF showing the game created in the article.
A GIF showing the game created in the article.

The first step is to create an HTML file with the general HTML structure, a canvas element, and a script tag (See figure 1). You could easily implement the JavaScript in a separate file instead, but for the sake of the tutorial, I decided to keep everything in a single file.

The canvas element will be used as the game’s scene, but you could also implement the game in other elements, such as a div tag, however, it will require some modifications to the code in this tutorial.

Figure 1: Shows the implementation of a simple HTML structure with a canvas and a script tag.

Before introducing the JavaScript code defining the game, I want to introduce some of the ideas behind the design. I decided to write the game using two different classes, TicTacToe and Square (See figure 2).

The class TicTacToe is used to instantiate the game by passing the id of a canvas element to the class’ constructor. This ensure the class can be used with several canvas elements on the same HTML page by simply creating multiple instances of the class for each canvas id.

The second class Square is used to represent a square on the board. This class keeps track of each square’s position, size, and whether or not a player has clicked on it. It also contains the behavior for drawing the visual of the square and the symbol of the player.

Figure 2: A UML Class diagram showing the classes used in the game.
Figure 2: A UML Class diagram showing the classes used in the game.

The Square class is used to instantiate a square object for each square for a 3×3 grid (see figure 3).

Figure 3: An illustration of a Square object instantiated by the Square class.
Figure 3: An illustration of a Square object instantiated by the Square class.

The class will require five properties: x; y; width; height; ctx; actor;

x and y define the square’s position, width and height define the square’s dimensions, ctx is a reference to the canvas’ rendering interface, and actor specifies the player who filled out the square with either an ‘x’ or ‘o’.

All the properties, except actor should be passed to the constructor upon instantiation (see figure 4). However, the actor property should be set to null within the constructor to ensure the property exists on Square objects.

Figure 4: Shows the implementation of the Square class constructor.

The class will also need a method, called draw() which is responsible for drawing a square and the symbol of the player who clicked on it.

The method calls another method on the ctx property called strokeRect(x, y, width, height) to draw the square (see figure 5, line 20). The ctx property also contains another property called strokeStyle which can be used to set the border’s color (see figure 5, line 19).

Figure 5: Shows the implementation of the Square class draw() method.

The draw method uses another method from the ctx property called fillText(text, x, y) to write the symbol of the player who clicked on the square (see figure 5, line 27). The text is positioned at the center of the square. The center position can be found by adding the square’s x and y position to half of its width and height (see figure 6). The ctx property contains another property called textAlign which can be set to center to ensure the text is aligned toward the center (see figure 5, line 26).

Figure 6: An illustration of how to find the center position of the square.
Figure 6: An illustration of how to find the center position of the square.

The next step is to create the TicTacToe class. The class will require a constructor and three methods: click(event); checkForWinner(); reset();

Figure 6: Shows the implementation of a TicTacToe class.

4.1 The Constructor

The constructor of the TicTacToe class is designed to require a string with the id of a canvas element to be instantiated.

The id is used to get an HTML canvas element with the specified id using the JavaScript function getElementById(id) and the element is set to a property called canvas (see figure 7, line 15).

After configuring the canvas property, the property is used to get an instance of its CanvasRenderingContext2Dwhich is set to a property called ctx (see figure 7, line 16). The ctx property provides the interface to draw within the canvas.

Figure 7: Shows the implementation of the TicTacToe class constructor.

The next step is to instantiate the Square objects. This is done by looping 3×3 and instantiating a Square object for each iteration which is added to a property called squares (see figure 7, lines 19–28).

The loop starts by creating a square at the position (x=0, y=0) and then loops from top to bottom until 9 squares are created (see figure 8).

Figure 10: Shows the different win combinations in Tic-tac-toe. The numbers represent the squares’ index in the squares array.
Figure 8: An illustration of the 3×3 loop finding each square’s position.

The class will require three other properties called actors, turn and gameOver (see figure 7, lines 31–37). actors is an array of two strings defining both the number of players and their symbols (‘x’ & ‘o’). turn defines a number between 0–1 which is specifying the actor from the actors array who should have the next turn. gameOver is a bool that returns true if the game is ended.

The last part of the constructor is to call the square objects draw() method and add a click event listener to the class’ click() method (see figure 7, lines 40–43).

4.2 The Click Method

The click method is designed to be executed whenever a user clicks on the canvas, and the position of the cursor at that moment can be read from the argument event.

The first section of the click method includes a guard clause which resets the game if the gameOver property is set to true. This gives the user the ability to start a new game by clicking on the canvas (see figure 9, lines 21–24).

Figure 9: Shows the implementation of the TicTacToe class click method.

The next part of the method loops all the Square objects and checks if the mouse position was within one of the squares. If the check evaluates to true, the current actor is added to the Square object’s actor property to signal the player has selected the square, and the turn property is set to either 0 or 1 to allow the next player to select a square (see figure 9, lines 27–43).

Last, the method calls the checkForWinner() method to see if a winner can be found (see figure 9, line 46).

4.3 The Check for Winner Method

The checkForWinner() method is designed to check if one of the players has selected three squares on a horizontal line, vertical line, or diagonal line (see figure 10).

Figure 10: Shows the different win combinations in Tic-tac-toe. The numbers represent the squares’ index in the squares array.
Figure 10: Shows the different win combinations in Tic-tac-toe. The numbers represent the squares’ index in the squares array.

The beginning of the method defines an array of arrays specifying the different win combinations (see figure 11, lines 26–33).

The array of arrays is used to loop all the win combinations and check whether or not three squares match one of the combinations (see figure 11, lines 36–66). If the check evaluates to true, the property gameOver is set to true to signal that the next click on the canvas should reset the game.

The method also draws a line showing the winner combination and writes a text displaying the winner (see figure 11, lines 54–63).

Figure 11: Shows the implementation of the TicTacToe class checkForWinner() method.

The last part of the method checks whether or not all the squares have an actor which is not null to see if the game should end as a draw. It is important the check is added after checking whether or not the game has a winner to avoid the game evaluating to a draw in cases where a winner is found by selecting the last empty square (see figure 11, lines 69–75).

4.4 The Reset Method

The reset method is designed to set the properties of an instance of the TicTacToe class to a state where the players can play a new game.

The method starts by clearing the pixels of the canvas by using the ctx property’s clearRect(x, y, width, height) method (see figure 12, line 31).

After clearing the pixels of the canvas, the squares’ actor property is set to null and the squares are drawn within the canvas again.

Last the method sets turn to 0 to reset the players turn, and set gameOver to false, to signal the click() method can add players to squares again and look for a new winner, or draw.

Figure 12: Shows the implementation of the TicTacToe class reset() method.

4.5 Starting the Game

The game is now ready to be played. Add a new line below the class definitions which creates a new instance of the class (see figure 13, line 13).

Figure 13: Shows how to start the Tic-tac-toe game.



News Credit

%d bloggers like this: