MAKING A TIC TAC TOE GAME IN MODERN JAVASCRIPT TUTORIAL (WITH ES6)

MAKING A TIC TAC TOE GAME IN MODERN JAVASCRIPT TUTORIAL (WITH ES6) 1

In our previous post, we have made the basic tic tac toe game with plain vanilla javascript. The purpose of this post is to replicate the same game using modern ES6 syntax: ie using class structures.
As you know from our article https://vuejstalk.com/top-10-es6-features-every-js-developer-must-know/
ES6 has added the class keywords and mechanism to implement class, constructors, methods, and inheritance like in any modern OOP languages. I think that will really help make our code even more readable and manageable.

For making this game initially we start with devising all the objects in this game.
1. Game :
Also known as game manager this class is responsible for managing gameplay, holding scores, checking winner and managing turns

2. GameUI:
This class is responsible for managing UI manipulation and updates such as score display,UI reset and event handling. As our game is fully event based we utilize this class for our event and ui manipulation.

3. Player
This class is responsible for holding and managing player info and its clicks.

2). Devising class structure

Game Class:

Properties:
players: array, list of players
winningCondition: array, list of winning positions
currentTurn: string, current turn (x/o)
drawScore: int, draw count
isGameEnded: int, is game running or not
_winningConditions: an array of string (winning condition joined as,)

Methods:

changeTurn() : change the current player (x=>O,O=>X)
reset() : reset the game
checkWinner() : checks for winner , winning condition
isGameOver() : checks whether game is over or not
getCombination() : get all possible combination in mxn

GameUI class:

Properties:
game: Game object

Methods:

initGame(): start game , manage initial events ,register event listeners
displayScore(): display scores
getTurnText(): display turn text
resetGame(): reset game UI

Player Class:

Properties

sign: display sign on grid click
clicks: list of all clicks made by the user
score: players overall score
combinations: all possible combination from players clicks
positions: player’s matchable click positions

Methods:

setPosition() : set the current position
sortClicks() : sort the clicks array

The algorithm and overall gameplay are almost the same as our previous example except for some differences in syntax and code structure.
The full javascript code is given below. You can find this code at our GitHub repository (https://github.com/sabinkhanal/tictactoejs)

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");

 

class GameUI {
constructor(game) {
this.game = game;
}

initGame() {
restartBtn.addEventListener("click", () => {
this.resetGame();
});

turnText.innerHTML = this.getTurnText();

[...buttons].forEach(btn => {
btn.addEventListener("click", e => {
if (btn.innerHTML.length > 0) {
alert("Already filled");
return;
}
btn.innerHTML = this.game.currentTurn;
this.game.changeTurn();
turnText.innerHTML = this.getTurnText();
setTimeout(() => {
if (this.game.checkWinner(btn) == true) {
this.displayScore();
this.resetGame();
}
}, 10);
e.preventDefault();
});
});
}

displayScore() {
p1_score.innerHTML = "Player 1:" + this.game.players[0].score;
draw_score.innerHTML = "Draw :" + this.game.drawScore;
p2_score.innerHTML = "Player 2:" + this.game.players[1].score;
}
getTurnText() {
return "TURN OF :" + this.game.currentTurn;
}
resetGame() {
console.log(this.game)
this.game.reset();
[...buttons].forEach(btn => {
btn.innerHTML = "";
this.game.currentTurn = this.game.players[0].sign;
});
}

}
class Player {
constructor(sign) {
this.sign = sign;
this.clicks = [];
this.score = 0;
this.combinations = [];
this.positions = []
}


setPosition() {
this.positions = this.clicks.join(",").split(",");
}
sortClicks() {
this.clicks.sort();
}

}

 

class Game {
constructor() {
this.players = []
this.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"]
];
this.currentTurn = "X";
this.drawScore = 0;
this.isGameEnded = false;
this._winningConditions =
this.winningCondition.map(x => x.join(","));
}
changeTurn() {
this.currentTurn = this.currentTurn == this.players[0].sign ? this.players[1].sign : this.players[0].sign;
}
reset() {
game.currentTurn = this.players[0].sign;
game.players.forEach(x => {
x.clicks = [];
})
}

checkWinner(btn) {
if (btn.innerHTML == this.players[0].sign) {
this.players[0].clicks.push(btn.id);
} else {
this.players[1].clicks.push(btn.id);
}

this.players.forEach(x => {
x.sortClicks()
x.setPosition();
})


if (this.players[0].positions.length > 2 || this.players[1].positions.length > 2) {

let player1_combinations = this.getCombination(this.players[0].positions, 3, 0);
console.log(player1_combinations)
let player2_combinations = this.getCombination(this.players[1].positions, 3, 0);

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

return this.isGameOver(player1_common, player2_common);
} else {
return false;
}
}

isGameOver(player1_common, player2_common) {
let gameOver = false;
if (player1_common > player2_common) {
gameOver = true
this.players[0].score += 1;
alert("Player One Won");
} else if (player2_common > player1_common) {
gameOver = true
this.players[1].score += 1;
alert("Player Two Won");
} else if (this.players[0].clicks.length > 4 || this.players[1].clicks.length > 4) {
gameOver = true
this.drawScore += 1;
alert("Draw");
} else {
gameOver = false
}
return gameOver;
}

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;
}
}

 

const game = new Game();
game.players.push(new Player("X"))
game.players.push(new Player("O"))
const ui = new GameUI(game)
ui.initGame();

 

If you have any problem understanding the code please let us know in the comment section below.

Please follow and like us:
MAKING A TIC TAC TOE GAME IN MODERN JAVASCRIPT TUTORIAL (WITH ES6) 2

Leave a Reply

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