<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">
<meta name="keywords" content="HTML, CSS, JavaScript, jQuery">
<meta name="author" content="Zia">
<meta name="Tic Tac Toe Game" content="The user can play a game of Tic Tac Toe with the computer. ">
<title>Tic Tac Toe Game</title>
</head>
<body>
<header id="showcase">
<h1>Tic Tac Toe Game</h1>
<div class="game-container">
<div class="inner-container">
<section class="section">
<div class="box" data-i=0 data-j=0></div>
<div class="box" data-i=0 data-j=1></div>
<div class="box" data-i=0 data-j=2></div>
</section>
<section class="section">
<div class="box" data-i=1 data-j=0></div>
<div class="box" data-i=1 data-j=1></div>
<div class="box" data-i=1 data-j=2></div>
</section>
<section class="section">
<div class="box" data-i=2 data-j=0></div>
<div class="box" data-i=2 data-j=1></div>
<div class="box" data-i=2 data-j=2></div>
</section>
</div>
</div>
<div class="winner"></div>
<div class="button">
<button id="restart">Restart</button>
</div>
</header>
<!-- Bootstrap Tether -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
</body>
</html>
html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
body{
margin: 0;
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
font-size: 18px;
color: #926239;
line-height: 1.6;
}
#showcase {
background-image: url('https://raw.githubusercontent.com/ziaongit/Tic-Tac-Toe-Game/master/resources/images/background.jpg');
height:100vh;
background-size: cover;
background-position: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0 20px;
}
#showcase h1 {
font-size: 50px;
text-align: center;
}
.game-container {
background: #926239;
width: 50%;
padding: 5px;
margin: 20px;
}
@media (max-width: 700px) {
.game-container {
width: 100%;
}
#showcase h1 {
font-size: 35px;
padding-top: 20px;
}
}
.inner-container {
width: 100%;
padding: 20px;
}
.section {
color: #fff;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.section .box {
background-color: #fff;
color: #926239;
width: 100px;
height: 100px;
line-height: 100px;
font-size: 40px;
margin: 2px;
text-align: center;
}
#showcase button {
font-size: 18px;
color: #926239;
border: 1px solid #926239;
padding: 10px 20px;
border-radius: 10px;
}
#showcase button:hover {
background-color: #926239;
color: #fff;
}
const PLAYER_TOKEN = 'X';
const COMPUTER_TOKEN = 'O';
$(document).ready(function() {
const grid = [
['', '', ''],
['', '', ''],
['', '', '']
];
function gameOver(grid) {
// Horizantal
for (var i = 0; i < 3; i++) {
if (grid[i][0] !== '' &&
grid[i][0] === grid[i][1] &&
grid[i][0] === grid[i][2]) {
return grid[i][0];
}
}
// Vertical
for (var j = 0; j < 3; j++) {
if (grid[0][j] !== '' &&
grid[0][j] === grid[1][j] &&
grid[0][j] === grid[2][j]) {
return grid[0][j];
}
}
// Diagonal - top left
if (grid[0][0] !== '' &&
grid[0][0] === grid[1][1] &&
grid[0][0] === grid[2][2]) {
return grid[0][0];
}
// Diagonal - bottom left
if (grid[2][0] !== '' &&
grid[2][0] === grid[1][1] &&
grid[2][0] === grid[0][2]) {
return grid[2][0];
}
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (grid[i][j] === '') {
return false;
}
}
}
return null;
}
function minmax(newGrid, depth, player) {
const gameState = gameOver(newGrid);
if (gameState === false) {
const values = [];
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
const gridCopy = _.cloneDeep(newGrid);
if (gridCopy[i][j] !== '') continue;
gridCopy[i][j] = player;
let value = minmax(gridCopy, depth + 1, ((player === PLAYER_TOKEN) ? COMPUTER_TOKEN : PLAYER_TOKEN));
values.push({
cost: value,
cell: {
i: i,
j: j
}
});
}
}
if (player === COMPUTER_TOKEN) {
const max = _.maxBy(values, (v) => {
return v.cost;
});
if (depth === 0) {
return max.cell;
} else {
return max.cost;
}
} else {
const min = _.minBy(values, (v) => {
return v.cost;
});
if (depth === 0) {
return min.cell;
} else {
return min.cost;
}
}
} else if (gameState === null) {
return 0;
} else if (gameState === PLAYER_TOKEN) {
return depth - 10;
} else if (gameState === COMPUTER_TOKEN) {
return 10 - depth;
}
}
function computerMove() {
return minmax(grid, 0, COMPUTER_TOKEN);
}
$('.box').click(function() {
let gameState = gameOver(grid);
if (gameState || gameState === null) {
return;
}
$this = $(this);
const i = $this.data('i');
const j = $this.data('j');
if (grid[i][j] !== '') {
return;
}
$this.html(PLAYER_TOKEN);
grid[i][j] = PLAYER_TOKEN;
gameState = gameOver(grid);
if (gameState) {
$('.winner').html('<p>Game over: ' + gameState + ' is the winner</p>');
setTimeout(function() {
$('.winner').html('');
}, 5000);
return;
} else if (gameState === null) {
$('.winner').html('<p>Game is drawn! Try again</p>');
setTimeout(function() {
$('.winner').html('');
}, 5000);
return;
} else {
const move = computerMove();
grid[move.i][move.j] = COMPUTER_TOKEN;
$('.box[data-i=' + move.i + '][data-j=' + move.j + ']').html(COMPUTER_TOKEN);
}
gameState = gameOver(grid);
if (gameState) {
$('.winner').html('<p>Game over: ' + gameState + ' is the winner</p>');
setTimeout(function() {
$('.winner').html('');
}, 5000);
}
});
$('#restart').click(function() {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
grid[i][j] = '';
$('.box[data-i=' + i + '][data-j=' + j + ']').html(' ');
}
}
});
});
Also see: Tab Triggers