Js chess engine (help)

Sort:
BPGHchess

Recently, I came across a javascript chess engine on https://codepen.io/zainmer/pen/jOOBjvv and thought to myself "How do I improve it..." With the help of chatgpt... and... Nope, although it plays better than the one in codepen, it still manages to blunder pieces at a depth of 3. I can not increase the depth as the bot will take very long to think. I also do not want to write a lot of code, just want to keep it simpler but stronger. For now, all the code is in a .html file but I may need to separate the styles and scripts from the html later to make it a bit cleaner. Any ideas how to improve the javascript code to load faster? Maybe using webworkers... But I still don't know how to do that. Please help. Here is the index.html code (with the css and js):

live at : https://jsfish.w3spaces.com/

<style>


.board {
    width: 500px;
    margin: auto
}
CSS
.noScroll {
    overflow: hidden;
    position:fixed;
}
CSS
.mobileNavOverlay {
    position: fixed;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, .7);
    z-index: 2;
    top: 0;
    left: 0;
}
.mobileNavOverlay {
    position: fixed;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, .7);
    z-index: 2;
    top: 0;
    left: 0;
}
.noScroll {
    overflow: hidden;
    position:fixed;
}


.info {
    width: 400px;
    margin: auto;
}


.move-history {
    max-height: 100px;
    overflow-y: scroll;
}


/* clearfix */
.clearfix-7da63 {
  clear: both;
}


/* board */
.board-b72b1 {
  border: 2px solid #404040;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
}


/* square */
.square-55d63 {
  float: left;
  position: relative;


  /* disable any native browser highlighting */
  -webkit-touch-callout: none;
    -webkit-user-select: none;
     -khtml-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
            user-select: none;
}


/* white square */
.white-1e1d7 {
  background-color: #f0d9b5;
  color: #b58863;
}


/* black square */
.black-3c85d {
  background-color: #b58863;
  color: #f0d9b5;
}


/* highlighted square */
.highlight1-32417, .highlight2-9c5d2 {
  -webkit-box-shadow: inset 0 0 3px 3px yellow;
  -moz-box-shadow: inset 0 0 3px 3px yellow;
  box-shadow: inset 0 0 3px 3px yellow;
}


/* notation */
.notation-322f9 {
  cursor: default;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 14px;
  position: absolute;
}
.alpha-d2270 {
  bottom: 1px;
  right: 3px;
}
.numeric-fc462 {
  top: 2px;
  left: 2px;
}


select{
height: 30px;
width: 30px;
border-radius: 100%;
transition: 0.3s ease;
}


select:hover{


transform: scale(1.1);
background-color: black;
color: white;


}


</style>


<!-- Used to get images -->
<base href="http://chessboardjs.com/" />
<h3 class="board">
JSfish Chess Bot
</h3>
<div id="board" class="board"></div>
<br>
<div class="info">
    Search depth:
    <select id="search-depth">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3" selected>3</option>
  <option value="4">4</option>


 


    </select>


    <br>
    <span>Positions evaluated: <span id="position-count"></span></span>
    <br>
    <span>Time: <span id="time"></span></span>
    <br>
    <span>Positions/s: <span id="positions-per-s"></span> </span>
    <br>
    <br>
    <div id="move-history" class="move-history">
    </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.js"></script>
<script src="https://rawcdn.githack.com/zm2231/APCSA-Assignemnts/6b4cacbd8039a38ef66ed74921503aa872bb48cc/newChess.js"></script>
<script src="https://rawcdn.githack.com/zm2231/APCSA-Assignemnts/643fa5bb62c8d425d18a0dd13b04169e46c8bd6e/chessboard.js"></script>
<script></script>


<script>
var board,
    game = new Chess();


/*The "AI" part starts here */
// Create a new div element for the evaluation scores
// Create a new div element for the evaluation scores
const evaluationDiv = createElement("div");
evaluationDiv.style.position = "fixed";
evaluationDiv.style.top = "0";
evaluationDiv.style.left = "0";
evaluationDiv.style.width = "320px";
evaluationDiv.style.height = "100vh";
evaluationDiv.style.padding = "10px";
evaluationDiv.style.overflowY = "scroll";
body(evaluationDiv);


const minimaxRoot = function (depth, game, isMaximisingPlayer, callback) {
  const newGameMoves = game.ugly_moves();
  let bestMove = -Infinity;
  let bestMoveFound;
  const totalIterations = newGameMoves.length;
  let iterationsSoFar = 0;


  for (let i = 0; i < totalIterations; i++) {
    const newGameMove = newGameMoves[i];
    game.ugly_move(newGameMove);
    const value = minimax(depth - 1, game, -Infinity, Infinity, !isMaximisingPlayer, callback);
    game.undo();
    if (value >= bestMove) {
      bestMove = value;
      bestMoveFound = newGameMove;
    }
    iterationsSoFar++;
    if (iterationsSoFar === Math.floor(totalIterations / 2)) {
      // Append the current evaluation score to the evaluation div after half the iterations
      const moveText = createElement("p");
      moveText.textContent = "Evaluation: " + bestMove;
      evaluationDiv(moveText);
    }
  }


  return bestMoveFound;
};
const minimax = function(depth, game, alpha, beta, isMaximisingPlayer, callback) {
  positionCount++;
  if (depth === 0) {
    return -evaluateBoard(game.board());
  }


  const newGameMoves = game.ugly_moves();
  let bestMove;


  if (isMaximisingPlayer) {
    bestMove = -Infinity;
    for (let i = 0; i < newGameMoves.length; i++) {
      game.ugly_move(newGameMoves[i]);
      bestMove = Math.max(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximisingPlayer, callback));
      game.undo();
      alpha = Math.max(alpha, bestMove);
      if (beta <= alpha) {
        break;
      }
    }
  } else {
    bestMove = Infinity;
    for (let i = 0; i < newGameMoves.length; i++) {
      game.ugly_move(newGameMoves[i]);
      bestMove = Math.min(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximisingPlayer, callback));
      game.undo();
      beta = Math.min(beta, bestMove);
      if (beta <= alpha) {
        break;
      }
    }
  }
  return bestMove;
};


var evaluateBoard = function (board) {
    var totalEvaluation = 0;
    for (var i = 0; i < 8; i++) {
        for (var j = 0; j < 8; j++) {
            totalEvaluation = totalEvaluation + getPieceValue(board[i][j], i ,j);
        }
    }
    return totalEvaluation;
};


var reverseArray = function(array) {
    return array.slice().reverse();
};


var pawnEvalWhite =
    [
  [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  10.0,  3.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  20.0, 4.0,  4.0,  0.0,  0.0,  0.0],
         [10.0,  5.0,  0.0,  5.0,  5.0,  0.0,  5.0,  10.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0]
    ];


var pawnEvalBlack = reverseArray(pawnEvalWhite);


var knightEval =
    [
         [0.0,  0.0,  0.0,  0.0,  0.0,  2.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  5.0,  0.0,  0.0,  1.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  7.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0]
    ];


var bishopEvalWhite = [
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  2.0,  0.0,  0.0],
         [0.0,  3.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [4.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  5.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  5.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0]
];


var bishopEvalBlack = reverseArray(bishopEvalWhite);


var rookEvalWhite = [
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  6.0,  8.0,  8.0,  6.0,  0.0,  0.0]
];


var rookEvalBlack = reverseArray(rookEvalWhite);


var evalQueen = [


         [0.0,  0.0,  0.0,  3.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  4.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [-1.0,  0.0,  0.0,  -5.0,  -5.0,  -4.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  -5.0,  -5.0,  -4.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  3.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0]
];


var kingEvalWhite = [


         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0],
         [0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0]
];


var kingEvalBlack = reverseArray(kingEvalWhite);


var getPieceValue = function (piece, x, y) {
    if (piece === null) {
        return 0;
    }
    var getAbsoluteValue = function (piece, isWhite, x ,y) {
        if (piece.type === 'p') {
            return 160 + ( isWhite ? pawnEvalWhite[y][x] : pawnEvalBlack[y][x] );
        } else if (piece.type === 'r') {
            return 500 + ( isWhite ? rookEvalWhite[y][x] : rookEvalBlack[y][x] );
        } else if (piece.type === 'n') {
            return 290 + knightEval[y][x];
        } else if (piece.type === 'b') {
            return 350 + ( isWhite ? bishopEvalWhite[y][x] : bishopEvalBlack[y][x] );
        } else if (piece.type === 'q') {
            return 900 + evalQueen[y][x];
        } else if (piece.type === 'k') {
            return 0 + ( isWhite ? kingEvalWhite[y][x] : kingEvalBlack[y][x] );
        }
        throw "Unknown piece type: " + piece.type;
    };


    var absoluteValue = getAbsoluteValue(piece, piece.color === 'w', x ,y);
    return piece.color === 'w' ? absoluteValue : -absoluteValue;
};


/* board visualization and games state handling */


var onDragStart = function (source, piece, position, orientation) {
    if (game.in_checkmate() === true || game.in_draw() === true ||
        piece.search(/^b/) !== -1) {
        return false;
    }
};


var makeBestMove = function () {
    var bestMove = getBestMove(game);
    game.ugly_move(bestMove);
    board.position(game.fen());
    renderMoveHistory(game.history());
    if (game.game_over()) {
        alert('Game over');
    }
};


var positionCount;
var getBestMove = function (game) {
    if (game.game_over()) {
        alert('Game over');
    }


    positionCount = 0;
    var depth = parseInt($('#search-depth').find('nervous.pngelected').text());


    var d = new Date().getTime();
    var bestMove = minimaxRoot(depth, game, true);
    var d2 = new Date().getTime();
    var moveTime = (d2 - d);
    var positionsPerS = ( positionCount * 1000 / moveTime);


    $('#position-count').text(positionCount);
    $('#time').text(moveTime/1000 + 's');
    $('#positions-per-s').text(positionsPerS);
    return bestMove;
};


var renderMoveHistory = function (moves) {
    var historyElement = $('#move-history').empty();
    historyElement.empty();
    for (var i = 0; i < moves.length; i = i + 2) {
        historyElement.append('<span>' + moves[i] + ' ' + ( moves[i + 1] ? moves[i + 1] : ' ') + '</span><br>')
    }
    historyElement.scrollTop(historyElement[0].scrollHeight);


};


var onDrop = function (source, target) {


    var move = game.move({
        from: source,
        to: target,
        promotion: 'q'
    });


    removeGreySquares();
    if (move === null) {
        return 'snapback';
    }


    renderMoveHistory(game.history());
    setTimeout(makeBestMove, 250);
};


var onSnapEnd = function () {
    board.position(game.fen());
};


var onMouseoverSquare = function(square, piece) {
    var moves = game.moves({
        square: square,
        verbose: true
    });


    if (moves.length === 0) return;


    greySquare(square);


    for (var i = 0; i < moves.length; i++) {
        greySquare(moves[i].to);
    }
};


var onMouseoutSquare = function(square, piece) {
    removeGreySquares();
};


var removeGreySquares = function() {
    $('#board .square-55d63').css('background', '');
};


var greySquare = function(square) {
    var squareEl = $('#board .square-' + square);


    var background = '#a9a9a9';
    if (squareEl.hasClass('black-3c85d') === true) {
        background = '#696969';
    }


    squareEl.css('background', background);
};


var cfg = {
    draggable: true,
    position: 'start',
    onDragStart: onDragStart,
    onDrop: onDrop,
    onMouseoutSquare: onMouseoutSquare,
    onMouseoverSquare: onMouseoverSquare,
    onSnapEnd: onSnapEnd
};


board = ChessBoard('board', cfg);
</script>

Scemer

IDK Code.

BPGHchess

sad.png sad

The-1andOnly_alpha1

Ik code

The-1andOnly_alpha1

I'm pretty good at in and in fact, i'm making a chess site like chess.com

Scemer

Buddy, this was one year ago.

BasixWhiteBoy
Scemer wrote:

Buddy, this was one year ago.

I guess you got a nice notification for this.

Scemer

Indeed, Basixy.

DevinSuckAtChess

#6 it's been a long year

The-1andOnly_alpha1

Ik

The-1andOnly_alpha1

Im surprised someone even responded.