Last active
August 22, 2018 16:35
-
-
Save Oscarz90/10d870b49d86e18e9fa899bc7db14e8f to your computer and use it in GitHub Desktop.
Implementation of Tic Tac Toe Game with certain level of AI.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* OMS | |
* August 2018 | |
**/ | |
/** | |
* Executes the move for a tic tac toe game given a player who plays the turn. | |
* @param {array} board The Board Game of tic tac toe with a state | |
* @param {string} player The player who plays the turn. | |
* @returns {array} board Returns the board with the move of the player | |
*/ | |
function game(board,player){ | |
// Tipes of players | |
const aPlayer="X", bPlayer="O"; | |
// Defines the opponent in base of the player input | |
let opponent = player==aPlayer?bPlayer:aPlayer; | |
/** | |
* Find all the empty cells of a boardGame | |
* @param {array} boardGame A game board with or without empty cells | |
* @returns {array} emptyIndexes Returns an array with the indexes of the emtpy cells of a given game board | |
*/ | |
function emtpyIndexes(boardGame){ | |
return boardGame.reduce((spots,cell,index)=>{ | |
if(cell!=aPlayer && cell!=bPlayer) | |
spots.push(index) | |
return spots | |
},[]) | |
} | |
/** | |
* Validates a game board to check if a player with a given role has won the game | |
* @param {array} boardGame A game board | |
* @param {string} temporalPlayer The player who plays the turn | |
* @returns {boolean} won Returns a boolean value, true if the player win, false on the contrary case | |
*/ | |
function validateGameBoardWinner(boardGame,temporalPlayer){ | |
// Valid scenarios for a player to win the game | |
const scenarios=[ | |
[0,1,2] | |
, [3,4,5] | |
, [6,7,8] | |
, [0,3,6] | |
, [1,4,7] | |
, [2,5,8] | |
, [0,4,8] | |
, [2,4,6] | |
] | |
//Validates all scenarios and returns the response. | |
return !!scenarios.find(scenario=>boardGame[scenario[0]]==temporalPlayer && boardGame[scenario[1]]==temporalPlayer && boardGame[scenario[2]]==temporalPlayer) | |
} | |
/** | |
* Find the best move for a given player and game board | |
* @param {*} boardGame The Board Game of tic tac toe with a state | |
* @param {*} temporalPlayer The player who plays the turn. | |
* @returns {object} bestMove Returns the best move for the given player | |
*/ | |
function findBestSpot(boardGame,temporalPlayer){ | |
// Obtains the available spots for the given game board | |
const availableSpots = emtpyIndexes(boardGame); | |
// Validates if the game ended | |
if(availableSpots.length==0){ | |
return {score:0}; | |
}else if(validateGameBoardWinner(boardGame,opponent)){ | |
return {score:-10}; | |
}else if(validateGameBoardWinner(boardGame,player)){ | |
return {score:10}; | |
} | |
const plays=[]; | |
// Evaluates the best moves for the emtpy cells | |
const moves = availableSpots.map((emtpyCellIndex,index)=>{ | |
let play ={index:emtpyCellIndex}, result; | |
boardGame[emtpyCellIndex] = temporalPlayer | |
if(temporalPlayer===player){ | |
play.score = findBestSpot(boardGame,opponent).score; | |
}else{ | |
play.score = findBestSpot(boardGame,player).score; | |
} | |
plays.push(play) | |
boardGame[emtpyCellIndex] = '-' | |
}) | |
// Find the best move of the move list | |
let findBest = plays.reduce((total,play)=>{ | |
if(play.score>total.bestScore){ | |
total.bestScore = play.score; | |
total.best = play | |
} | |
return total; | |
},{bestScore:-100000,best:undefined}) | |
// Returns the best move | |
return findBest.best | |
} | |
// Finds the best move for the given game board | |
const findTheBestMove = findBestSpot(board,player); | |
// Makes the move on the game board | |
board[findTheBestMove.index] = player; | |
// Returns the new board game's state | |
return board; | |
} | |
/** | |
* Examples | |
* Board Game Tic Tac Toe | |
* O | X | X | |
* X | - | - | |
* X | O | O | |
* Symbol "-" means emtpy | |
* The algorithm decides the best move for its turn | |
* The turn is for the player who is playin with "O" | |
* | |
* After execute the function it will return the board as this. | |
* O | X | X | |
* X | O | - | |
* X | O | O | |
*/ | |
const board = ["O","X","X","X","-","-","X","O","O"] | |
console.log(game(board,"O")) | |
/** | |
* Examples | |
* Board Game Tic Tac Toe | |
* X | - | O | |
* - | - | - | |
* - | X | - | |
* Symbol "-" means emtpy | |
* The algorithm decides the best move for its turn | |
* The turn is for the player who is playin with "X" | |
* | |
* After execute the function it will return the board as this. | |
* X | X | O | |
* - | - | - | |
* - | X | - | |
*/ | |
const boardTwo = ["X","-","O","-","-","-","-","X","-"] | |
console.log(game(boardTwo,"X")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO
: Implement difficulty easy, medium and hard, it should decide using a difficulty preset that will affect directly in the way that the algorithm choose the best move, maybe not choosing the best move, an "alternative move", emulating a "mistake" due to is the only way of a player to win against the AI