Unbeatable Tic Tac Toe. Single-page HTML, CSS & JavaScript.
Implementation of Minimax algorithm wrapped up in a neat chalkboard UI. The chalk effect is achieved using SVG turbulence filters.
Minimax algorithm:
Lines 438 to 482 in 3e10e64
| function getComputerMoveData(tempPlaygroundState, depth) { | |
| const winCombinationIndex = getWinCombinationIndex(tempPlaygroundState); | |
| if (winCombinationIndex !== -1) { | |
| // we've got a winner in this hypothetical game! | |
| const wonMover = tempPlaygroundState[winCombinations[winCombinationIndex][0]]; | |
| return { | |
| index: -1, | |
| score: wonMover === 1 | |
| ? -1 // user hypothetically won (bad) | |
| : 1 // computer hypothetically won (good) | |
| }; | |
| } else if (!tempPlaygroundState.some((mover) => mover === -1)) { | |
| // a tie | |
| return { index: -1, score: 0 }; | |
| } | |
| depth = (depth || 0) + 1; | |
| // 1 - user's hypothetical turn; 0 - computer's hypothetical turn. | |
| const mover = +!(depth % 2); | |
| const availableMoves = tempPlaygroundState | |
| .map((_, i) => i) | |
| .filter((boardIndex) => tempPlaygroundState[boardIndex] === -1); | |
| const scores = []; | |
| const moves = []; | |
| for (let i = 0; i < availableMoves.length; i++) { | |
| const move = availableMoves[i]; | |
| const iterationPlayground = [ ...tempPlaygroundState ]; | |
| iterationPlayground[move] = mover; | |
| const hypotheticalMoveData = getComputerMoveData(iterationPlayground, depth); | |
| scores.push(hypotheticalMoveData.score); | |
| moves.push(move); | |
| // rollback the hypothetical move | |
| tempPlaygroundState[move] = -1; | |
| } | |
| const func = mover === 1 | |
| ? Math.min // we're looking for the min score if it's user's turn | |
| : Math.max; // and for the max score if it's computer's score | |
| const moveScore = func.apply(null, scores); | |
| const moveScoreIndex = scores.indexOf(moveScore); | |
| return { index: moves[moveScoreIndex], score: moveScore }; | |
| } |