Making games is a great way to learn programming. It’s not just fun but also teaches us how to use complex logic and implement UI and logic binding. Tic Tac Toe is the best choice for beginners to start on with game development. Making tictactoe helps you to grasp the concept of arrays, UI logic binding as well as event handling.

 

The purpose of this post is to show you how to create a simple tic tac toe game using just plain old javascript. (except some arrow functions). We’ll try to make our code as simple as possible and try to not compromise on the quality of code as possible. For checking winning positions I’ve been following a custom method which you might not see in other code snippets. I think this approach is better than lengthy if else conditions.

Here’s the HTML code for our game. It has a title, Turn display, Score display and reset button with buttons aligned in a grid fashion. Each button has given an id of the respective row and column values. This helps us to easily check the player’s input position later on.

 

<!DOCTYPE html>
<html lang="en">
<head>
<title>Title</title>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<!-- Bootstrap CSS -->
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="tictactoe.css"></link>
</head>
<body>
<div class="text-center">
<h1>Tic Tac Toe</h1>
<h3 id="turnText"></h3> 
<div class="score">
<span><u>Scores</u></span><br>
<span id="p1_score">Player One :</span>
<span id="p2_score">Player Two :</span>
<span id="draw_score">Draw :</span>
</div>
<button class="replay" id="restartBtn">Restart</button>
</div>
<div class="gamebox" style="margin-top:20px">
<button id="00"></button>
<button id="01"></button>
<button id="02"></button>
<button id="10"></button>
<button id="11"></button>
<button id="12"></button>
<button id="20"></button>
<button id="21"></button>
<button id="22"></button>
</div>
<script src="tictactoe.js"></script>
</body>
</html>

 

 

Here’s the basic css for our game. We have just included the basic styling as we are putting our main focus on javascript instead.

–tictactoe.css

.gamebox button {
width: 100px;
height: 100px;
border: 1px solid #000;
display: inline-block;
font-size: 30px;
color: #fff;
}
.gamebox {
margin: 0 auto;
max-width: 300px;
display: grid;
justify-items: center;
align-content: space-around;
grid-template-columns: repeat(3, 1fr);
}
.replay {
border: 1px solid #ddd;
height: 60px;
margin-top: 20px;
padding: 10px;
}

 

 

Here comes the scripting part. we are implementing all our logic in plain simple javascript. (we’ll also post another tutorial for the same game with more modern constructs such as ES6 and class /oop based syntax).

We initially start with fetching all UI elements and assigning them to the js variables. Most of the code is self-explanatory and commented well.

tictactoe.js

//fetch common ui elements

let buttons = document.querySelectorAll(".gamebox button");

 let turnText = document.getElementById("turnText");

 let restartBtn = document.getElementById("restartBtn");

 let p1_score = document.getElementById("p1_score");

 let p2_score = document.getElementById("p2_score"); 

let draw_score = document.getElementById("draw_score");




//declare variables

let players = ["X", "O"];

let winningCondition = [
["00", "01", "02"],
["00", "11", "22"],
["00", "10", "20"],
["02", "11", "20"],
["10", "11", "12"],
["02", "12", "22"],
["01", "11", "21"],
["20", "21", "22"]
];

let currentTurn = players[0];
let player1_hit = [];
let player2_hit = [];
var player1_combinations = [];
var player2_combinations = [];
let p1score = 0;
let p2score = 0;
let drawScore = 0;
turnText.innerHTML = getTurnText();
//reset event handle




restartBtn.addEventListener("click", function() {
resetGame();
});



//for each buttons add click event
[...buttons].forEach(btn => {
btn.addEventListener("click", e => {
if (btn.innerHTML.length > 0) {
alert("already filled");
return;
}




//if clicked,fill with current sign
btn.innerHTML = currentTurn;
//change current turn
currentTurn = currentTurn == players[0] ? players[1] : players[0];
//display turn text
turnText.innerHTML = getTurnText();
//check winner with some delay(rendering time)




setTimeout(() => checkWinner(btn), 10);
e.preventDefault();
});
});







function resetGame() {
//reset game to initial state
currentTurn = players[0];
player1_hit = [];
player2_hit = [];
player1_combinations = [];
player2_combinations = [];

[...buttons].forEach(btn => {
btn.innerHTML = "";
currentTurn = players[0];
});
}







function getTurnText() {
//turn text string
return "TURN OF :" + currentTurn;

}



//get (mxn) combination of array
function getCombination(input, len, start) {
const result = new Array(3);
let combinations = new Array();
combine(input, len, start);

function combine(input, len, start) {
if (len === 0) {
combinations.push(result.join(","));
return;
}
for (var i = start; i <= input.length - len; i++) {
result[result.length - len] = input[i];
combine(input, len - 1, i + 1);
}
}
return combinations;
}


//check winner
function checkWinner(btn) {
//insert into players hit list
if (btn.innerHTML == players[0]) {
player1_hit.push(btn.id);
} else {
player2_hit.push(btn.id);
}
//sort hitlist
player1_hit.sort();
player2_hit.sort();




//create string version of hit array and split to make array
let player1_pos = player1_hit.join(",").split(",");
let player2_pos = player2_hit.join(",").split(",");




//winning condition matching pos array
let _winningConditions = winningCondition.map(x => x.join(","));
//once hit more than 2 times , check for winner

if (player1_hit.length > 2 || player2_hit.length > 2) {
let player1_combinations = getCombination(player1_pos, 3, 0);
let player2_combinations = getCombination(player2_pos, 3, 0);

//find p1,p2 common with winning conditions
let player1_common = _winningConditions.filter(value =>
player1_combinations.includes(value));

let player2_common = _winningConditions.filter(value =>
player2_combinations.includes(value)
);

let isGameEnded = false;
//if winning condition matches , show who is winner

if (player1_common > player2_common) {
isGameEnded = true;
p1score += 1;
alert("Player One Won");
}

else if (player2_common > player1_common) {
isGameEnded = true;
p2score += 1;
alert("Player Two Won");
}

else if (player1_hit.length > 4 || player2_hit.length > 4) {
isGameEnded = true;
drawScore += 1;
alert("Draw");
}

if (isGameEnded) {
displayScore();
resetGame();
}

}

}

function displayScore() {

p1_score.innerHTML = "Player 1:" + p1score;
p2_score.innerHTML = "Player 2:" + p2score;
draw_score.innerHTML = "Draw :" + drawScore;

}

 


We have applied a little bit different approach for checking winning moves.

After the user hits more than 2 buttons. we apply the following procedure to find the winning move.

Define the winning condition as an array of CSV strings with (row,column) position

eg:[ [“00,01,02”],[“00,11,22”]]

Then we create similar CSV for user’s clicks based on id of clicked buttons.

eg: player1_pos=[00,11,02,22]

Then we generate all the possible winning moves from the user’s clicks array. we use combine method above which accepts 3 parameters : array, length of combination string to make and starting position.

The target array would be like :

[“00,11,22″,”00,11,02″,”00,02,22″,”11,02,22”]

After that we sort the above array and find the intersection with the presorted winning conditions.

 

We have used the following method for finding intersection array.

 

let player1_common = _winningConditions.filter(value =>
player1_combinations.includes(value)
);

 

if the length of intersection array is more than 0 and if player 1’s intersection size is more than that we can say that player 1 is a winner. In a similar way, we find another matrix for player 2. The condition which was not matched in both cases would be the draw situation.

In this way, we can create a simple tic tac toe game in Html, CSS and JS. In our next post, we’ll try to post the code of tic tac toe using modern ES6 and class-based syntax. Please do’not forgot to bookmark our website.

You can find the full working source code in our github repository .

https://github.com/sabinkhanal/tictactoejs

Thank You.

 

Leave a Reply

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