Skip to content

Instantly share code, notes, and snippets.

@Pragalbha-Patil
Created August 11, 2019 14:46
Show Gist options
  • Save Pragalbha-Patil/8f09d11cf09ad249767da0df8649f459 to your computer and use it in GitHub Desktop.
Save Pragalbha-Patil/8f09d11cf09ad249767da0df8649f459 to your computer and use it in GitHub Desktop.
A javascript Tic-tac-toe using Minimax algorithm
var origBoard;
const huPlayer = 'O';
const aiPlayer = 'X';
const winCombos = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[6, 4, 2]
]
const cells = document.querySelectorAll('.cell');
startGame();
function startGame() {
document.querySelector(".endgame").style.display = "none";
origBoard = Array.from(Array(9).keys());
for (var i = 0; i < cells.length; i++) {
cells[i].innerText = '';
cells[i].style.removeProperty('background-color');
cells[i].addEventListener('click', turnClick, false);
}
}
function turnClick(square) {
if (typeof origBoard[square.target.id] == 'number') {
turn(square.target.id, huPlayer)
if (!checkWin(origBoard, huPlayer) && !checkTie()) turn(bestSpot(), aiPlayer);
}
}
function turn(squareId, player) {
origBoard[squareId] = player;
document.getElementById(squareId).innerText = player;
let gameWon = checkWin(origBoard, player)
if (gameWon) gameOver(gameWon)
}
function checkWin(board, player) {
let plays = board.reduce((a, e, i) =>
(e === player) ? a.concat(i) : a, []);
let gameWon = null;
for (let [index, win] of winCombos.entries()) {
if (win.every(elem => plays.indexOf(elem) > -1)) {
gameWon = { index: index, player: player };
break;
}
}
return gameWon;
}
function gameOver(gameWon) {
for (let index of winCombos[gameWon.index]) {
document.getElementById(index).style.backgroundColor =
gameWon.player == huPlayer ? "blue" : "red";
}
for (var i = 0; i < cells.length; i++) {
cells[i].removeEventListener('click', turnClick, false);
}
declareWinner(gameWon.player == huPlayer ? "You win!" : "You lose.");
}
function declareWinner(who) {
document.querySelector(".endgame").style.display = "block";
document.querySelector(".endgame .text").innerText = who;
}
function emptySquares() {
return origBoard.filter(s => typeof s == 'number');
}
function bestSpot() {
return minimax(origBoard, aiPlayer).index;
}
function checkTie() {
if (emptySquares().length == 0) {
for (var i = 0; i < cells.length; i++) {
cells[i].style.backgroundColor = "yellow";
cells[i].removeEventListener('click', turnClick, false);
}
declareWinner("Tie Game!")
return true;
}
return false;
}
function minimax(newBoard, player) {
var availSpots = emptySquares();
if (checkWin(newBoard, huPlayer)) {
return { score: -10 };
} else if (checkWin(newBoard, aiPlayer)) {
return { score: 10 };
} else if (availSpots.length === 0) {
return { score: 0 };
}
var moves = [];
for (var i = 0; i < availSpots.length; i++) {
var move = {};
move.index = newBoard[availSpots[i]];
newBoard[availSpots[i]] = player;
if (player == aiPlayer) {
var result = minimax(newBoard, huPlayer);
move.score = result.score;
} else {
var result = minimax(newBoard, aiPlayer);
move.score = result.score;
}
newBoard[availSpots[i]] = move.index;
moves.push(move);
}
var bestMove;
if (player === aiPlayer) {
var bestScore = -10000;
for (var i = 0; i < moves.length; i++) {
if (moves[i].score > bestScore) {
bestScore = moves[i].score;
bestMove = i;
}
}
} else {
var bestScore = 10000;
for (var i = 0; i < moves.length; i++) {
if (moves[i].score < bestScore) {
bestScore = moves[i].score;
bestMove = i;
}
}
}
return moves[bestMove];
}
td{
border: 2px solid #333;
height: 100px;
width: 100px;
text-align: center;
vertical-align: middle;
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 70px;
cursor: pointer;
}
table{
border-collapse: collapse;
position: relative;
left: 50%;
margin-left: -155px;
top: 50px;
}
table tr:first-child td{
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child {
border-left: 0;
}
table tr td:last-child {
border-right: 0;
}
.endgame{
display: none;
width: 200px;
top:120px;
background-color: green;
position: absolute;
left: 50%;
margin-left: -100px;
padding-top: 50px;
padding-bottom: 50px;
text-align: center;
border-radius: 5px;
color: white;
font-size: 2em;
}
<!DOCTYPE html>
<html>
<head>
<link href="style.css" rel="stylesheet">
<title>AI plays Tic Tac Toe </title>
</head>
<body>
<div class="row"><center>Can the AI beat you?</center>
</div>
<br>
<table>
<tr>
<td class="cell" id="0"></td>
<td class="cell" id="1"></td>
<td class="cell" id="2"></td>
</tr>
<tr>
<td class="cell" id="3"></td>
<td class="cell" id="4"></td>
<td class="cell" id="5"></td>
</tr>
<tr>
<td class="cell" id="6"></td>
<td class="cell" id="7"></td>
<td class="cell" id="8"></td>
</tr>
</table>
<br>
<div class="endgame">
<div class="text"></div>
<button onclick="startGame()">Restart</button>
</div>
<script src="script.js"></script>
</body>
</html>
@AKASHRAWAT45
Copy link

Untitled
sir i am getting
const cells = document.querySelectorAll('.cell');
^

ReferenceError: document is not defined
error.please help...and please tell me how to run this code perfectly

@Pragalbha-Patil
Copy link
Author

Untitled
sir i am getting
const cells = document.querySelectorAll('.cell');
^

ReferenceError: document is not defined
error.please help...and please tell me how to run this code perfectly

You're trying to run this code on Node, but the gist requires you to have a DOM (i.e. you should include the script in an HTML document) and run it instead of running it directly. I've also attached the HTML & CSS code for the same, refer that.

@JanviArora123
Copy link

Hey! Can you please give an instance in your tic tac toe game where human beats computer . Because everytime i play its the computer who wins always

@Kitketovsky
Copy link

It's a bit late to say, but anyway. It's quite a small chance for a human to win a game against minimax algorightm AI in tic-tac-toe - around 5% or less. The explanation.

@HungEEI
Copy link

HungEEI commented Mar 21, 2023

5x5 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment