visit
I recommend you to exercise what you see so that you will get the most out of this article. The source code can be found at my . Open your favorite IDE, mine is VSCode, and open a new project folder. We will create the files one by one. This will be our directory structure:
|- index.html
|- /js
|- main.js
|- /stylesheet
|- main.css
Let's start with the index.html. In the body of the html, we will add the title, form for filling player names, a submit button to play, container for clickable boxes, and restart button. Remember to also put links to your stylesheet at the top and your script at the bottom. The container to play the game will be invisible at first. After the players fill the form and click submit, we will make the container visible.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="styles/styles.css">
<title>TICTACTOE</title>
</head>
<body>
<h2 class="text-center mt-4">Tic<span class="mid-title">Tac</span>Toe</h2>
<h5 class="text-center"> Enter players' names and click play to start the game!</h5>
<div class="container">
<form class="player-info mb-4">
<div class="form-group">
<label for="player1">Player 1 (X)</label>
<input type="text" class="form-control" id="player1" placeholder="Name of player 1">
</div>
<div class="form-group">
<label for="player2">Player 2 (O)</label>
<input type="text" class="form-control" id="player2" placeholder="Name of player 2">
</div>
<button type="submit" class="btn btn-primary">Play</button>
</form>
<div class="col-4 offset-4 place hidden">
<div class="alert alert-primary game-status text-center">
<h4>Board:</h4>
</div>
<div class="container mx-auto">
<div id="board">
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
<div class="cell text-center display-4"></div>
</div>
</div>
<button id="reset" class="mt-4 text-center btn btn-primary">Restart</button>
</div>
</div>
<script src="js/main.js"></script>
</body>
</html>
In the main.css file, we will add our styles. I've used bootswatch. It is a customized version of bootstrap. You can your own style if you want. Go ahead to their website, choose a theme and download the minified css and put that at the top the css file. I have added my own style after shown below. You have to add the bootswatch minified css at the top of this file.
#board {
border: 2px solid black;
display: flex;
flex-wrap: wrap;
height: 270px;
width: 245px;
}
.cell {
border: 2px solid black;
height: 80px;
width: 80px;
}
.hidden {
display: none;
}
.player-info, .game-status {
width: 80%;
}
.mid-title {
color: red;
}
Ok, now let's go to the main part, main.js file. All methods below this paragraph are JavaScript methods that will be in the main.js file.Let's start with the playerFactory. The playerFactory will be the factory for players. Factories are like classes. You can also use class instead of factory but factories are preferred. You can read more about classes and factories . The playerFactory will accept the player name and the mark ('X' or 'O'). It will have a method to play when it's the player's turn. The playTurn method will accept a board which will be the game board and the cell. It will find the index of the cell and return it if it's empty or it will return null if it's occupied.
const playerFactory = (name, mark) => {
const playTurn = (board, cell) => {
const idx = board.cells.findIndex(position => position === cell);
if (board.boardArray[idx] === '') {
board.render();
return idx;
}
return null;
};
return { name, mark, playTurn };
};
const boardModule = (() => {
let boardArray = ['', '', '', '', '', '', '', '', ''];
const gameBoard = document.querySelector('#board');
const cells = Array.from(document.querySelectorAll('.cell'));
let winner = null;
const render = () => {
boardArray.forEach((mark, idx) => {
cells[idx].textContent = boardArray[idx];
});
};
const reset = () => {
boardArray = ['', '', '', '', '', '', '', '', ''];
};
const checkWin = () => {
const winArrays = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
winArrays.forEach((combo) => {
if (boardArray[combo[0]]
&& boardArray[combo[0]] === boardArray[combo[1]]
&& boardArray[combo[0]] === boardArray[combo[2]]) {
winner = 'current';
}
});
return winner || (boardArray.includes('') ? null : 'Tie');
};
return {
render, gameBoard, cells, boardArray, checkWin, reset,
};
})();
const gamePlay = (() => {
const playerOneName = document.querySelector('#player1');
const playerTwoName = document.querySelector('#player2');
const form = document.querySelector('.player-info');
const resetBtn = document.querySelector('#reset');
let currentPlayer;
let playerOne;
let playerTwo;
const switchTurn = () => {
currentPlayer = currentPlayer === playerOne ? playerTwo : playerOne;
};
const gameRound = () => {
const board = boardModule;
const gameStatus = document.querySelector('.game-status');
if (currentPlayer.name !== '') {
gameStatus.textContent = `${currentPlayer.name}'s Turn`;
} else {
gameStatus.textContent = 'Board: ';
}
board.gameBoard.addEventListener('click', (event) => {
event.preventDefault();
const play = currentPlayer.playTurn(board, event.target);
if (play !== null) {
board.boardArray[play] = `${currentPlayer.mark}`;
board.render();
const winStatus = board.checkWin();
if (winStatus === 'Tie') {
gameStatus.textContent = 'Tie!';
} else if (winStatus === null) {
switchTurn();
gameStatus.textContent = `${currentPlayer.name}'s Turn`;
} else {
gameStatus.textContent = `Winner is ${currentPlayer.name}`;
board.reset();
board.render();
}
}
});
};
const gameInit = () => {
if (playerOneName.value !== '' && playerTwoName.value !== '') {
playerOne = playerFactory(playerOneName.value, 'X');
playerTwo = playerFactory(playerTwoName.value, 'O');
currentPlayer = playerOne;
gameRound();
}
};
form.addEventListener('submit', (event) => {
event.preventDefault();
if (playerOneName.value !== '' && playerTwoName.value !== '') {
gameInit();
form.classList.add('hidden');
document.querySelector('.place').classList.remove('hidden');
} else {
window.location.reload();
}
});
resetBtn.addEventListener('click', () => {
document.querySelector('.game-status').textContent = 'Board: ';
document.querySelector('#player1').value = '';
document.querySelector('#player2').value = '';
window.location.reload();
});
return {
gameInit,
};
})();
gamePlay.gameInit();