From 9f7e3901dc69e764d1cd8d69b2e987af6afc79aa Mon Sep 17 00:00:00 2001 From: byanofsky Date: Mon, 3 Jul 2017 17:03:58 -0700 Subject: [PATCH] Add comments and JSdoc to calcBestMove --- public/js/movecalc.js | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/public/js/movecalc.js b/public/js/movecalc.js index c44dca8..2f88b46 100644 --- a/public/js/movecalc.js +++ b/public/js/movecalc.js @@ -87,57 +87,70 @@ var calcBestMoveN = function(depth, game, isMaximizingPlayer) { return [bestMoveValue, bestMove]; } -// Calculate the best move using Minimax with Alpha Beta Pruning. -// Provide depth and game as params. -var calcBestMove = function(depth, game, playerColor, alpha=Number.NEGATIVE_INFINITY, - beta=Number.POSITIVE_INFINITY, - isMaximizingPlayer=true) { - // Base case: return current board position +/** + * Calculates the best move using Minimax with Alpha Beta Pruning. + * @param {Number} depth - How many moves ahead to evaluate + * @param {Object} game - The game to evaluate + * @param {string} playerColor - Players color, either 'b' or 'w' + * @param {Number} alpha + * @param {Number} beta + * @param {Boolean} isMaximizingPlayer - If current turn is maximizing or minimizing player + * @return {Array} The best move value, and the best move + */ +var calcBestMove = function(depth, game, playerColor, + alpha=Number.NEGATIVE_INFINITY, + beta=Number.POSITIVE_INFINITY, + isMaximizingPlayer=true) { + // Base case: evaluate board if (depth === 0) { value = evaluateBoard(game.board(), playerColor); return [value, null] } - var bestMove = null; + // Recursive case: search possible moves + var bestMove = null; // best move not set yet var possibleMoves = game.moves(); - // Randomize possible moves + // Set random order for possible moves possibleMoves.sort(function(a, b){return 0.5 - Math.random()}); - // Set a default best move value var bestMoveValue = isMaximizingPlayer ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY; // Search through all possible moves for (var i = 0; i < possibleMoves.length; i++) { var move = possibleMoves[i]; + // Make the move, but undo before exiting loop game.move(move); + // Recursively get the value from this move value = calcBestMove(depth-1, game, playerColor, alpha, beta, !isMaximizingPlayer)[0]; - + // Log the value of this move console.log(isMaximizingPlayer ? 'Max: ' : 'Min: ', depth, move, value, bestMove, bestMoveValue); if (isMaximizingPlayer) { - // Assign best move if is appropriate for player position + // Look for moves that maximize position if (value > bestMoveValue) { bestMoveValue = value; bestMove = move; } alpha = Math.max(alpha, value); } else { - // Assign best move if is appropriate for player position + // Look for moves that minimize position if (value < bestMoveValue) { bestMoveValue = value; bestMove = move; } beta = Math.min(beta, value); } - + // Undo previous move game.undo(); + // Check for alpha beta pruning if (beta <= alpha) { console.log('Prune', alpha, beta); break; } } - + // Log the best move at the current depth console.log('Depth: ' + depth + ' | Best Move: ' + bestMove + ' | ' + bestMoveValue + ' | A: ' + alpha + ' | B: ' + beta); + // Return the best move, or the only move return [bestMoveValue, bestMove || possibleMoves[0]]; }