mirror of
https://github.com/neogeek23/neogeek23.github.io.git
synced 2026-02-04 02:48:17 +00:00
194 lines
6.1 KiB
JavaScript
194 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, source, target){
|
|
let nextMove = undefined;
|
|
if (this.difficulty === 'Random'){
|
|
nextMove = this.determineSimplestBotMove(game, source, target);
|
|
} else if (this.difficulty === 'Easy') {
|
|
nextMove = this.determineNextBestBotMoveOneMoveDeep(game, source, target);
|
|
} 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, source, target){
|
|
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, source, target) {
|
|
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, source, target);
|
|
} 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;
|
|
}
|
|
}
|
|
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, source, target), 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);
|
|
}
|