├── README.md ├── script.js ├── style.css └── tictactoe.html /README.md: -------------------------------------------------------------------------------- 1 | # AI-tictactoe 2 | created Ai using minimax Algorithms in game Theory 3 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | var origBoard; 2 | const huPlayer = 'O'; 3 | const aiPlayer = 'X'; 4 | const winCombos = [ 5 | [0, 1, 2], 6 | [3, 4, 5], 7 | [6, 7, 8], 8 | [0, 3, 6], 9 | [1, 4, 7], 10 | [2, 5, 8], 11 | [0, 4, 8], 12 | [6, 4, 2] 13 | ] 14 | 15 | const cells = document.querySelectorAll('.cell'); 16 | startGame(); 17 | 18 | function startGame() { 19 | document.querySelector(".endgame").style.display = "none"; 20 | origBoard = Array.from(Array(9).keys()); 21 | for (var i = 0; i < cells.length; i++) { 22 | cells[i].innerText = ''; 23 | cells[i].style.removeProperty('background-color'); 24 | cells[i].addEventListener('click', turnClick, false); 25 | } 26 | } 27 | 28 | function turnClick(square) { 29 | if (typeof origBoard[square.target.id] == 'number') { 30 | turn(square.target.id, huPlayer) 31 | if (!checkWin(origBoard, huPlayer) && !checkTie()) turn(bestSpot(), aiPlayer); 32 | } 33 | } 34 | 35 | function turn(squareId, player) { 36 | origBoard[squareId] = player; 37 | document.getElementById(squareId).innerText = player; 38 | let gameWon = checkWin(origBoard, player) 39 | if (gameWon) gameOver(gameWon) 40 | } 41 | 42 | function checkWin(board, player) { 43 | let plays = board.reduce((a, e, i) => 44 | (e === player) ? a.concat(i) : a, []); 45 | let gameWon = null; 46 | for (let [index, win] of winCombos.entries()) { 47 | if (win.every(elem => plays.indexOf(elem) > -1)) { 48 | gameWon = {index: index, player: player}; 49 | break; 50 | } 51 | } 52 | return gameWon; 53 | } 54 | 55 | function gameOver(gameWon) { 56 | for (let index of winCombos[gameWon.index]) { 57 | document.getElementById(index).style.backgroundColor = 58 | gameWon.player == huPlayer ? "blue" : "red"; 59 | } 60 | for (var i = 0; i < cells.length; i++) { 61 | cells[i].removeEventListener('click', turnClick, false); 62 | } 63 | declareWinner(gameWon.player == huPlayer ? "You win!" : "You lose."); 64 | } 65 | 66 | function declareWinner(who) { 67 | document.querySelector(".endgame").style.display = "block"; 68 | document.querySelector(".endgame .text").innerText = who; 69 | } 70 | 71 | function emptySquares() { 72 | return origBoard.filter(s => typeof s == 'number'); 73 | } 74 | 75 | function bestSpot() { 76 | return minimax(origBoard, aiPlayer).index; 77 | } 78 | 79 | function checkTie() { 80 | if (emptySquares().length == 0) { 81 | for (var i = 0; i < cells.length; i++) { 82 | cells[i].style.backgroundColor = "green"; 83 | cells[i].removeEventListener('click', turnClick, false); 84 | } 85 | declareWinner("Tie Game!") 86 | return true; 87 | } 88 | return false; 89 | } 90 | 91 | function minimax(newBoard, player) { 92 | var availSpots = emptySquares(); 93 | 94 | if (checkWin(newBoard, huPlayer)) { 95 | return {score: -10}; 96 | } else if (checkWin(newBoard, aiPlayer)) { 97 | return {score: 10}; 98 | } else if (availSpots.length === 0) { 99 | return {score: 0}; 100 | } 101 | var moves = []; 102 | for (var i = 0; i < availSpots.length; i++) { 103 | var move = {}; 104 | move.index = newBoard[availSpots[i]]; 105 | newBoard[availSpots[i]] = player; 106 | 107 | if (player == aiPlayer) { 108 | var result = minimax(newBoard, huPlayer); 109 | move.score = result.score; 110 | } else { 111 | var result = minimax(newBoard, aiPlayer); 112 | move.score = result.score; 113 | } 114 | 115 | newBoard[availSpots[i]] = move.index; 116 | 117 | moves.push(move); 118 | } 119 | 120 | var bestMove; 121 | if(player === aiPlayer) { 122 | var bestScore = -10000; 123 | for(var i = 0; i < moves.length; i++) { 124 | if (moves[i].score > bestScore) { 125 | bestScore = moves[i].score; 126 | bestMove = i; 127 | } 128 | } 129 | } else { 130 | var bestScore = 10000; 131 | for(var i = 0; i < moves.length; i++) { 132 | if (moves[i].score < bestScore) { 133 | bestScore = moves[i].score; 134 | bestMove = i; 135 | } 136 | } 137 | } 138 | 139 | return moves[bestMove]; 140 | } 141 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | td { 2 | border: 2px solid #333; 3 | height: 100px; 4 | width: 100px; 5 | text-align: center; 6 | vertical-align: middle; 7 | font-family: "Comic Sans MS", cursive, sans-serif; 8 | font-size: 70px; 9 | cursor: pointer; 10 | } 11 | 12 | table { 13 | border-collapse: collapse; 14 | position: absolute; 15 | left: 50%; 16 | margin-left: -155px; 17 | top: 50px; 18 | } 19 | 20 | table tr:first-child td { 21 | border-top: 0; 22 | } 23 | 24 | table tr:last-child td { 25 | border-bottom: 0; 26 | } 27 | 28 | table tr td:first-child { 29 | border-left: 0; 30 | } 31 | 32 | table tr td:last-child { 33 | border-right: 0; 34 | } 35 | 36 | .endgame { 37 | display: none; 38 | width: 200px; 39 | top: 120px; 40 | background-color: rgba(205,133,63, 0.8); 41 | position: absolute; 42 | left: 50%; 43 | margin-left: -100px; 44 | padding-top: 50px; 45 | padding-bottom: 50px; 46 | text-align: center; 47 | border-radius: 5px; 48 | color: white; 49 | font-size: 2em; 50 | } 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tictactoe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |17 | | 18 | | 19 | |
22 | | 23 | | 24 | |
27 | | 28 | | 29 | |