I have programmed a Tic Tac Toe game using Object Oriented JavaScript and ES6 Classes.
The program works as planned, but I wonder if some parts of the code can be made cleaner or more efficient.
I'm mostly concerned with the JS parts, not the HTML or CSS.
Here is the code:
index.html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="main.css">
</head>
<body>
<h2 id="title">Tic Tac Toe</h2>
<div class="container" id="board">
<div class="row">
<div class="square" id="00"></div>
<div class="square" id="01"></div>
<div class="square" id="02"></div>
</div>
<div class="row">
<div class="square" id="10"></div>
<div class="square" id="11"></div>
<div class="square" id="12"></div>
</div>
<div class="row">
<div class="square" id="20"></div>
<div class="square" id="21"></div>
<div class="square" id="22"></div>
</div>
</div>
<button id="new-game">New Game</button>
<h3 id="message"></h3>
<script src="objects.js"></script>
<script src="main.js"></script>
</body>
</html>
main.css
body {
text-align: center;
font-family: Arial, Helvetica, sans-serif;
}
.square {
display: inline-block;
width: 185px;
height: 165px;
margin: 3px;
background-color: #bfbfbf;
vertical-align: top;
font-size: 700%;
color: red;
}
.row {
min-width: 600px ;
}
#new-game {
margin: 10px;
}
#message {
font-size: 3em;
}
objects.js
'use strict'
class Board {
constructor(grid) {
this.grid = [
[new Square(), new Square(), new Square()],
[new Square(), new Square(), new Square()],
[new Square(), new Square(), new Square()]
];
}
isFull() {
let count = 0;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (this.grid[i][j].state != "") { count++ }
}
}
if (count == 9) {
return true;
}
else {
return false;
}
}
check_win() {
for (let i = 0; i < 3; i++) {
if (this.grid[i][0].state == this.grid[i][1].state && this.grid[i][0].state == this.grid[i][2].state && this.grid[i][0].state != "") {
print_winner();
}
}
for (let j = 0; j < 3; j++) {
if (this.grid[0][j].state == this.grid[1][j].state && this.grid[0][j].state == this.grid[2][j].state && this.grid[0][j].state != "") {
print_winner();
}
}
if ((this.grid[0][0].state == this.grid[1][1].state && this.grid[0][0].state == this.grid[2][2].state && this.grid[0][0].state != "") ||
(this.grid[0][2].state == this.grid[1][1].state && this.grid[0][2].state == this.grid[2][0].state && this.grid[0][2].state != "")) {
print_winner();
}
if (this.isFull()) {
print_tie();
}
}
}
class Square {
constructor(state) {
this.state = "";
}
whoseTurn() {
if (counter == 0) {
return this.state = "x";
}
else {
return this.state = "o";
}
}
}
class Player {
constructor(symbol) {
this.symbol = symbol;
}
}
class Game {
constructor() {
this.board = new Board();
this.players = [
new Player("x"),
new Player("o")
];
}
}
main.js
'use strict'
var g = new Game();
var counter = 0;
function play() {
let bd = document.getElementById('board');
bd.addEventListener('click', (event) => {
// console.log(event.target);
event.target.innerHTML = g.players[counter].symbol;
var squareNum = event.target.id.split('');
var row = squareNum[0];
var col = squareNum[1];
g.board.grid[row][col].whoseTurn();
g.board.check_win();
if (counter == 0) { counter = 1 }
else { counter = 0 }
});
}
function print_winner() {
let winner = g.players[counter].symbol;
console.log(`${winner} wins`);
}
function print_tie() {
console.log("It's a tie");
}
function play_again() {
let bt = document.getElementById('new-game');
bt.addEventListener('click', () => {
for (let i = 0; i < 9; i++) {
document.querySelectorAll('.square')[i].innerHTML = "";
}
g = new Game();
});
}
play();
play_again();