2018-08-30 00:34:17 -05:00

199 lines
6.1 KiB
JavaScript

const maxBoardLength = 8;
window.onload = function(){chess_main();};
class ChessBot{
constructor(difficulty, color){
this.difficulty = difficulty;
this.color = color;
}
makeMove(game, board){
let nextMove = undefined;
if (this.difficulty === 'Random'){
nextMove = this.determineSimplestBotMove(game);
} else if (this.difficulty === 'Easy') {
nextMove = this.determineNextBestBotMoveOneMoveDeep(game);
} else if (this.difficulty === 'Medium'){
let depth = Math.floor(Math.random() * 1 + 2);
console.clear();
console.log(depth + " moves ahead.");
nextMove = this.determineBestBotMove(depth, game, true);
}
if (nextMove !== undefined) {
game.move(nextMove);
board.position(game.fen());
}else {
throw "difficulty not recognized" + this.difficulty;
}
}
determineSimplestBotMove(game){
let possibleMoves = game.moves();
if (possibleMoves.length === 0) return;
let randomIndex = Math.floor(Math.random() * possibleMoves.length);
return possibleMoves[randomIndex];
}
getWhitePieceWeight(piece){
if (piece.type === 'p'){
return 10;
} else if (piece.type === 'r'){
return 50;
} else if (piece.type === 'n'){
return 30;
} else if (piece.type === 'b'){
return 35;
} else if (piece.type === 'q'){
return 90;
} else if (piece.type === 'k'){
return 900;
}
throw "Unknown piece type: " + piece.type;
}
getPieceValue(piece){
if(piece === null){
return 0;
}
return piece.color === 'w' ? this.getWhitePieceWeight(piece) : -this.getWhitePieceWeight(piece);
}
evaluateBoardForWhite(game){
let totalEvaluation = 0;
for (let i = 0; i < maxBoardLength; i++){
for (let j = 0; j < maxBoardLength; j++){
totalEvaluation += this.getPieceValue(game.get(String.fromCharCode(97 + i) + (j + 1)));
}
}
return totalEvaluation;
}
evaluateBoardForBlack(game){return -this.evaluateBoardForWhite(game);}
determineNextBestBotMoveOneMoveDeep(game) {
let bestMove = null;
let bestValue = -9999;
let boardValue = 0;
let possibleMoves = game.moves();
for (let i = 0; i < possibleMoves.length; i++) {
let newGameMove = possibleMoves[i];
game.move(newGameMove);
if (this.color === "w") {
boardValue = this.evaluateBoardForWhite(game);
} else if (this.color === "b") {
boardValue = this.evaluateBoardForBlack(game);
} else {
throw "Unknown bot team color: " + this.color;
}
game.undo();
if (boardValue > bestValue) {
bestValue = boardValue;
bestMove = newGameMove;
}
}
if (bestValue === 0) {
return this.determineSimplestBotMove(game);
} else {
return bestMove;
}
}
determineBestBotMove(depth, game, isMaximizingPlayer){
let possibleMoves = game.moves();
let bestValue = -9999;
let bestMove;
for (let i = 0; i < possibleMoves.length; i++){
game.move(possibleMoves[i])
let currentValue = this.mini_max_AB(depth - 1, game, -10000, 10000, !isMaximizingPlayer);
game.undo();
if(currentValue >= bestValue){
bestMove = possibleMoves[i];
bestValue = currentValue;
}
}
if (bestValue === 0) {
return this.determineSimplestBotMove(game);
} else {
return bestMove;
}
}
mini_max_AB(depth, game, alpha, beta, isMaximizingPlayer){
if (depth === 0 && this.color === 'w'){
return this.evaluateBoardForWhite(game);
} else if (depth === 0 && this.color === 'b') {
return this.evaluateBoardForBlack(game);
}
let possibleMoves = game.moves();
let bestValue = 9999 * (isMaximizingPlayer ? -1 : 1);
for (let i = 0; i < possibleMoves.length; i++){
game.move(possibleMoves[i]);
if (isMaximizingPlayer){
bestValue = Math.max(bestValue, this.mini_max_AB(depth-1, game, alpha, beta, !isMaximizingPlayer));
alpha = Math.max(alpha, bestValue);
} else {
bestValue = Math.min(bestValue, this.mini_max_AB(depth-1, game, alpha, beta, !isMaximizingPlayer));
beta = Math.min(beta, bestValue);
}
game.undo();
if (beta <= alpha){
return bestValue;
}
}
return bestValue;
}
}
function chess_main() {
let game = new Chess();
let board = ChessBoard('board');
let BBot = new ChessBot('Medium', 'b');
setupChess(game, board, BBot);
}
function setupChess(game, board, bot){
let onDragStart = function(source, piece, position, orientation) {
if (game.in_checkmate() === true || game.in_draw() === true ||
piece.search(/^b/) !== -1) {
return false;
}
};
let onDrop = function(source, target) {
let move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for example simplicity
});
if (move === null) return 'snapback';
window.setTimeout(bot.makeMove(game, board), 250);
};
let onSnapEnd = function() {
board.position(game.fen());
};
let cfg = {
draggable: true,
dropOffBoard: 'snapback',
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
};
board = ChessBoard('board', cfg);
}