Im trying to build tic tac toe game using javascript, so basically my version of tic tac toe is without AI so computer play in the first empty spot (as you can see in bestSpot() function) then I replace it with a minimax function to make computer unbeatable (from this repo: sourcecode) when I tried to combine it to my code I get an error [see attached pic][]2. i couldn't figure whats wrong with minimax function that throws an error. any help will be much appreciable. (to disable minimax uncomment first line in bestSpot() function) NOTE: PLEASE EXPAND FULL-VIEW SNIPPET TO SKIP PAGE RESPONSIVE ERRORS.
var currentPlayer = '';
var computerPlayer = '';
var playerSelection = [];
var computerSelection = [];
var boardInputs = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const winCombos = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[1, 4, 7],
[2, 5, 8],
[3, 6, 9],
[1, 5, 9],
[7, 5, 3]
]
$(document).ready(function() {
$('.board').hide();
$('.restart').hide();
// $('.mine').hide();
choseSign();
});
function choseSign() {
$('.choseSq').on('click', function() {
var element = $(this).attr('value');
console.log('element player', element);
if (element == 'o' || element == 'x') {
currentPlayer += element;
$('.mine').fadeOut(500);
$('.board').fadeIn(3000);
if (currentPlayer === 'x') {
computerPlayer = 'o';
} else {
computerPlayer = 'x';
}
startGame();
}
});
}
function startGame() {
document.getElementById('tictactoe').style.pointerEvents = 'auto';
$('.square').on('click', function() {
var element2 = $(this).attr('value');
var myIndex = playerSelection.indexOf(parseInt(element2));
var comIndex = computerSelection.indexOf(parseInt(element2));
if (myIndex === -1 && comIndex === -1) {
if (currentPlayer == 'o') {
$(this).append("<img src='http://www.dreamincode.net/forums/uploads/monthly_10_2010/post-0-12884151170642.png'/>");
boardInputs[parseInt(element2) - 1] = currentPlayer;
console.log('board: ', boardInputs);
} else {
$(this).append("<img src='http://www.dreamincode.net/forums/uploads/post-97990-1260678617.png'/>");
boardInputs[parseInt(element2) - 1] = currentPlayer;
console.log('board: ', boardInputs);
}
playerSelection.push(parseInt(element2));
console.log('current player: ', playerSelection);
let gameWon = checkWin(boardInputs, currentPlayer);
if (gameWon) {
gameOver(gameWon, 'you won');
} else if (playerSelection.length < 6) {
document.getElementById('tictactoe').style.pointerEvents = 'none';
console.log('##CUR PLY: ', currentPlayer, '$$%AI PLY: ', computerPlayer)
setTimeout(() => {
computerTurn(bestSpot(), computerPlayer);
}, 1000);
}
} else {
console.log('Position Taken !');
}
});
}
function computerTurn(squareId, player) {
document.getElementById('tictactoe').style.pointerEvents = 'auto';
//var random_number = Math.floor(Math.random() * (9 - 1 + 1)) + 1;
console.log("SQR_ID: ", squareId);
//boardInputs[squareId] = computerPlayer;
var playerIndex = playerSelection.indexOf(squareId);
var computerIndex = computerSelection.indexOf(squareId);
var generatePosition = '.sq';
if (playerIndex === -1 && computerIndex === -1) {
computerSelection.push(squareId);
generatePosition += squareId
console.log("genPos: ", generatePosition);
if (currentPlayer === 'x') {
$(generatePosition).append("<img src='http://www.dreamincode.net/forums/uploads/monthly_10_2010/post-0-12884151170642.png'/>");
boardInputs[squareId - 1] = computerPlayer;
} else {
$(generatePosition).append("<img src='http://www.dreamincode.net/forums/uploads/post-97990-1260678617.png'/>");
boardInputs[squareId - 1] = computerPlayer;
}
console.log('board: ', boardInputs);
let gameWon = checkWin(boardInputs, computerPlayer);
if (gameWon) {
gameOver(gameWon, 'Computer won');
}
} else {
if (computerSelection.length < 4) {
computerTurn(bestSpot(), computerPlayer);
} else {
console.log('it\'s a -- DRAW -- Game Finished');
console.log('board result', boardInputs);
$('.status').text('its a draw');
$('.restart').show();
$('.RestartBtn').on('click', function() {
clearGame();
$('.restart').hide();
});
}
}
console.log("computer board: ", computerSelection);
}
function clearGame() {
for (i = 1; i < 10; i++) {
var sq = '.sq' + i;
$(sq).text('');
$(sq).css("background-color", "rgb(248, 248, 248)");
}
$('.board').hide();
$('.mine').fadeIn(1500);
currentPlayer = '';
computerPlayer = '';
playerSelection = [];
computerSelection = [];
boardInputs = [];
boardInputs = [1, 2, 3, 4, 5, 6, 7, 8, 9];
}
function checkWin(board, player) {
let plays = board.reduce((a, e, i) =>
(e === player) ? a.concat(i + 1) : 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, status) {
document.getElementById('tictactoe').style.pointerEvents = 'none';
for (let index of winCombos[gameWon.index]) {
var square = '.sq' + index;
$(square).css("background-color", "rgb(41, 168, 62)");
}
setTimeout(() => {
$('.status').text(status);
$('.restart').show();
// $('.board').hide();
}, 1000);
$('.RestartBtn').on('click', function() {
clearGame();
$('.restart').hide();
});
}
function emptySquares() {
// console.log('emt func')
return boardInputs.filter(s => typeof s === 'number');
// return boardInputs.filter((elm, i) => i === elm);
}
function bestSpot() {
// return emptySquares()[0]; // uncomment to disable minimax algorithem
return minimax(boardInputs, computerPlayer).index; // comment to disable minimax
}
function minimax(newBoard, player) {
var availSpots = emptySquares(newBoard);
console.log('aviSpt: ', availSpots);
if (checkWin(newBoard, currentPlayer)) {
return {
score: -10
};
} else if (checkWin(newBoard, computerPlayer)) {
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 == computerPlayer) {
var result = minimax(newBoard, currentPlayer);
move.score = result.score;
} else {
var result = minimax(newBoard, computerPlayer);
move.score = result.score;
}
newBoard[availSpots[i]] = move.index;
moves.push(move);
}
var bestMove;
if (player === computerPlayer) {
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];
}
body {
background: rgb(248, 248, 248);
text-transform: capitalize;
font-family: 'Architects Daughter', cursive;
}
.game {
width: 433px;
height: 433px;
}
.board {
align-items: center;
align-content: center;
height: 399px;
width: 399px;
margin: auto;
margin-top: 20px;
}
/* .restart{
border: 2px solid rgb(201, 23, 23);
display: inline-flex;
height: 149px;
width: 299px;
left: 38%;
background-color: rgb(255, 255, 255);
margin-bottom:-82px;
} */
/* .extraline{
border: 2px solid rgb(23, 201, 47);
position: absolute;
align-items: center;
align-content: center;
height: 149px;
width: 299px;
background-color: rgb(255, 255, 255);
} */
.chose {
/* text-transform: capitalize;
color: rgb(201, 23, 23);
border: 8px solid rgb(41, 168, 62);
position: absolute;
align-items: center;
align-content: center;
height: 349px;
width: 299px;
margin: auto;
background-color: rgb(255, 255, 255);
text-align: center;
margin-left: 53px; */
}
img {
height: 60px;
width: 60px;
margin: 29px 0 0 29px;
}
.center {
margin: auto;
width: 40%;
margin-top: 93px;
}
.square {
border: 5px solid rgb(201, 23, 23);
float: left;
width: 120px;
height: 120px;
overflow: hidden;
}
.squarex {
border: 6px solid red;
float: left;
position: relative;
width: 400px;
height: 1px;
padding-bottom: 30%;
/* = width for a 1:1 aspect ratio */
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
/* you change this to "contain" if you don't want the images to be cropped */
margin-top: -4px;
}
.x2 {
border: 6px solid green;
height: 150px;
width: 400px;
display: inline-block;
margin-right: -4px;
}
#rec1 {
border: 5px solid rgb(41, 168, 62);
border-top-color: rgb(248, 248, 248);
border-left-color: rgb(248, 248, 248);
border-bottom-color: rgb(218, 172, 25);
}
#rec2 {
border: 5px solid rgb(218, 172, 25);
border-top-color: rgb(248, 248, 248);
border-right-color: rgb(137, 60, 153);
border-bottom-color: rgb(113, 216, 54);
}
#rec3 {
border-top-color: rgb(248, 248, 248);
border-right-color: rgb(248, 248, 248);
border-bottom-color: rgb(153, 60, 77);
}
#rec4 {
border-left-color: rgb(248, 248, 248);
border-bottom-color: rgb(248, 248, 248);
border-right-color: rgb(153, 60, 77);
border-top-color: rgb(0, 162, 211);
}
#rec5 {
border-bottom-color: rgb(248, 248, 248);
border-right-color: rgb(39, 131, 173);
border-top-color: rgb(176, 0, 211);
border-left-color: rgb(68, 187, 161);
text-align: center;
color: rgb(209, 16, 16);
font-size: 25px;
font-weight: bold;
}
#rec6 {
border-right-color: rgb(248, 248, 248);
border-bottom-color: rgb(248, 248, 248);
border-left-color: rgb(236, 202, 48);
border-top-color: rgb(36, 128, 233);
}
.restart {
position: absolute;
text-align: center;
}
.choseSq {
border-radius: 22px;
margin: auto;
width: 100px;
padding-bottom: 25px;
padding-right: 27px;
display: inline;
}
.choseSq:hover {
background-color: rgb(255, 223, 223);
}
.sq1 {
border: 5px solid rgb(25, 116, 103);
border-top-color: rgb(248, 248, 248);
border-left-color: rgb(248, 248, 248);
}
.sq2 {
border: 5px solid rgb(39, 131, 173);
border-top-color: rgb(248, 248, 248);
}
.sq3 {
border: 5px solid rgb(236, 202, 48);
border-top-color: rgb(248, 248, 248);
border-right-color: rgb(248, 248, 248);
}
.sq4 {
border: 5px solid rgb(151, 153, 60);
border-left-color: rgb(248, 248, 248);
}
.sq5 {
border: 5px solid rgb(153, 60, 77);
}
.sq6 {
border: 5px solid rgb(60, 69, 153);
border-right-color: rgb(248, 248, 248);
}
.sq7 {
border: 5px solid rgb(137, 60, 153);
border-left-color: rgb(248, 248, 248);
border-bottom-color: rgb(248, 248, 248);
}
.sq8 {
border: 5px solid rgb(218, 172, 25);
border-bottom-color: rgb(248, 248, 248);
}
.sq9 {
border: 5px solid rgb(41, 168, 62);
border-right-color: rgb(248, 248, 248);
border-bottom-color: rgb(248, 248, 248);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
<link href="https://fonts.googleapis.com/css?family=Architects+Daughter" rel="stylesheet">
</head>
<body>
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
<div class="restart">
<h1 class="status"></h1>
<h2>Restart the game?</h2>
<button class='RestartBtn'>Restart</button>
</div>
<div class="mine">
<div id="rec1" class="x2">
</div>
<div id="rec2" class="x2">
</div>
<div id="rec3" class="x2">
</div>
<div id="rec4" class="squarex">
</div>
<div id="rec5" class="squarex ">
<h2>Please Chose a sign to start a game</h2>
<div class=" choseSq" value="x">
<img src="http://www.dreamincode.net/forums/uploads/post-97990-1260678617.png" />
</div>
<div class=" choseSq" value="o">
<img src="http://www.dreamincode.net/forums/uploads/monthly_10_2010/post-0-12884151170642.png" />
</div>
</div>
<div id="rec6" class="squarex">
</div>
</div>
<div class="game center">
<div class="board" id='tictactoe'>
<div class="square sq1" value="1">
</div>
<div class="square sq2" value="2">
</div>
<div class="square sq3" value="3">
</div>
<div class="square sq4" value="4">
</div>
<div class="square sq5" value="5">
</div>
<div class="square sq6" value="6">
</div>
<div class="square sq7" value="7">
</div>
<div class="square sq8" value="8">
</div>
<div class="square sq9" value="9">
</div>
</div>
</div>
<script src="script.js" type="text/javascript"></script>
</body>
</html>