UNPKG

@karmacarrot/minotaur-chess-engine

Version:

A chess engine for JavaScript projects.

1,061 lines (1,053 loc) 119 kB
// src/logging/definitions.ts var LogLevels = /* @__PURE__ */ ((LogLevels2) => { LogLevels2[LogLevels2["warn"] = 0] = "warn"; LogLevels2[LogLevels2["log"] = 1] = "log"; LogLevels2[LogLevels2["error"] = 2] = "error"; LogLevels2[LogLevels2["info"] = 3] = "info"; return LogLevels2; })(LogLevels || {}); // src/logging/logger.config.ts var LoggerConfig = { verbosity: 2 /* error */, enableEvaluationLogs: true }; // src/logging/logger.ts function MultiLog(outputType, message, outputVerbosity) { if ((outputType === 0 /* warn */ || outputType === 3 /* info */) && outputVerbosity === 2 /* error */) { return; } if (outputType === 3 /* info */ && outputVerbosity !== 3 /* info */) { return; } switch (outputType) { case 3 /* info */: console.info(message); case 0 /* warn */: console.warn(message); case 2 /* error */: console.error(message); case 1 /* log */: console.log(message); default: console.log(message); } } // src/helpers/definitions.ts var InitialGameStatus = { isWhitesTurn: true, isGameOver: false, moveHistory: [], positionEvaluation: 0, blackComputerControl: true, whiteComputerControl: false, blackKingChecked: false, whiteKingChecked: false, whiteKingCanCastleLong: true, whiteKingCanCastleShort: true, blackKingCanCastleLong: true, blackKingCanCastleShort: true, lastWhiteDoublePawnMove: BigInt(0), lastBlackDoublePawnMove: BigInt(0) }; var numberOfTiles = 64; var xOrYTileLength = 8; var blackStartingRank = 7; var whiteStartingRank = 2; var files = ["a", "b", "c", "d", "e", "f", "g", "h"]; var aTogFilesOnly = BigInt( "0b0000000100000001000000010000000100000001000000010000000100000001" ); var bTohFilesOnly = BigInt( "0b1000000010000000100000001000000010000000100000001000000010000000" ); var a1 = BigInt("0b1000000000000000000000000000000000000000000000000000000000000000"); var h8 = BigInt("0b0000000000000000000000000000000000000000000000000000000000000001"); var StartingBoard = { whitePawn: BigInt("0b0000000011111111000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0100001000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0010010000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000001111111100000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000001000010"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000100100"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000001"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var EmptyBoard = { whitePawn: BigInt(0), whiteKnight: BigInt(0), whiteBishop: BigInt(0), whiteRook: BigInt(0), whiteQueen: BigInt(0), whiteKing: BigInt(0), blackPawn: BigInt(0), blackKnight: BigInt(0), blackBishop: BigInt(0), blackRook: BigInt(0), blackQueen: BigInt(0), blackKing: BigInt(0), none: BigInt(0) }; var allOnes = BigInt("0b1111111111111111111111111111111111111111111111111111111111111111"); var BoardArrangements = /* @__PURE__ */ ((BoardArrangements2) => { BoardArrangements2[BoardArrangements2["StartingPositions"] = 0] = "StartingPositions"; BoardArrangements2[BoardArrangements2["MiddleGame"] = 1] = "MiddleGame"; BoardArrangements2[BoardArrangements2["EndGame"] = 2] = "EndGame"; BoardArrangements2[BoardArrangements2["DuellingPawns"] = 3] = "DuellingPawns"; BoardArrangements2[BoardArrangements2["EmptyBoard"] = 4] = "EmptyBoard"; BoardArrangements2[BoardArrangements2["MiniMaxOne"] = 5] = "MiniMaxOne"; BoardArrangements2[BoardArrangements2["MateInOneForBlackGameBoard"] = 6] = "MateInOneForBlackGameBoard"; BoardArrangements2[BoardArrangements2["MateInOneForWhiteGameBoard"] = 7] = "MateInOneForWhiteGameBoard"; BoardArrangements2[BoardArrangements2["CastleForBlackGameBoard"] = 8] = "CastleForBlackGameBoard"; BoardArrangements2[BoardArrangements2["BlackLongCastledGameBoard"] = 9] = "BlackLongCastledGameBoard"; BoardArrangements2[BoardArrangements2["BlackShortCastledGameBoard"] = 10] = "BlackShortCastledGameBoard"; BoardArrangements2[BoardArrangements2["CastleForBlackAfter"] = 11] = "CastleForBlackAfter"; BoardArrangements2[BoardArrangements2["EnPassantBoard"] = 12] = "EnPassantBoard"; return BoardArrangements2; })(BoardArrangements || {}); var pieceImages = { whitePawn: "pawn_w", //white pawns whiteKnight: "knight_w", //white knights whiteBishop: "bishop_w", //white bishops whiteRook: "rook_w", //white rooks whiteQueen: "queen_w", //white queen whiteKing: "king_w", //white king blackPawn: "pawn_b", //black pawns blackKnight: "knight_b", //black knights blackBishop: "bishop_b", //black bishops blackRook: "rook_b", //black rooks blackQueen: "queen_b", //black queen blackKing: "king_b" //black king. }; var slidingPieces = [ "whitePawn", "whiteBishop", "whiteQueen", "whiteKing", "whiteRook", "blackPawn", "blackBishop", "blackQueen", "blackKing", "blackRook" ]; var unicodePieceMap = { whiteKing: "\u2654", whiteQueen: "\u2655", whiteRook: "\u2656", whiteBishop: "\u2657", whiteKnight: "\u2658", whitePawn: "\u2659", blackKing: "\u265A", blackQueen: "\u265B", blackRook: "\u265C", blackBishop: "\u265D", blackKnight: "\u265E", blackPawn: "\u265F" }; var pieceValues = { pawn: 1, knight: 3, bishop: 3, rook: 5, queen: 9, king: 20 }; var CentralDominanceWeightings = { absoluteCentre: BigInt("0b0000000000000000000000000001100000011000000000000000000000000000"), innerRing: BigInt("0b0000000000000000001111000010010000100100001111000000000000000000"), outerRing: BigInt("0b0000000001111110010000100100001001000010010000100111111000000000") }; var RankWeightings = { secondRank: BigInt("0b0000000011111111000000000000000000000000000000000000000000000000"), seventhRank: BigInt("0b0000000000000000000000000000000000000000000000001111111100000000") }; var EvalWeightings = { absoluteCentreWeight: 0.3, innerRingWeight: 0.1, outerRingWeight: 0, oneMoveUntilPromotionWeight: 6, pawnChainWeight: 0.1, developedBishopKnight: 0.2, developedRook: 0, //TODO: revisit this, maybe we should only consider connected rooks to be 'developed'? freedomToMove: 0.01, safeKing: 2 }; var evalLoggingOn = { evalLayers: [], evalLoggingEnabled: true, evalAddNode: () => { return; } }; var evalLoggingOff = { evalLayers: [], evalLoggingEnabled: false, evalAddNode: () => { return; } }; var knightMoveOffsets = [17, 15, 10, 6, -6, -10, -15, -17]; var diagonalOffsets = [9, -9, 7, -7]; var orthagonalOffsets = [1, -1, 8, -8]; var fullBitMask = (BigInt(1) << BigInt(64)) - BigInt(1); var blackKingShortCastleRoute = BigInt( "0b0000000000000000000000000000000000000000000000000000000000000110" ); var blackKingLongCastleRoute = BigInt( "0b0000000000000000000000000000000000000000000000000000000001110000" ); var whiteKingShortCastleRoute = BigInt( "0b0000011000000000000000000000000000000000000000000000000000000000" ); var whiteKingLongCastleRoute = BigInt( "0b0111000000000000000000000000000000000000000000000000000000000000" ); var blackKingShortCastleDestination = BigInt( "0b0000000000000000000000000000000000000000000000000000000000000010" ); var blackKingLongCastleDestination = BigInt( "0b0000000000000000000000000000000000000000000000000000000000100000" ); var whiteKingShortCastleDestination = BigInt( "0b0000001000000000000000000000000000000000000000000000000000000000" ); var whiteKingLongCastleDestination = BigInt( "0b0100000000000000000000000000000000000000000000000000000000000000" ); var blackKingShortCastleRookDestination = BigInt( "0b0000000000000000000000000000000000000000000000000000000000000100" ); var blackKingLongCastleRookDestination = BigInt( "0b0000000000000000000000000000000000000000000000000000000000010000" ); var whiteKingShortCastleRookDestination = BigInt( "0b0000001000000000000000000000000000000000000000000000000000000000" ); var whiteKingLongCastleRookDestination = BigInt( "0b0001000000000000000000000000000000000000000000000000000000000000" ); var blackKingShortRook = BigInt( "0b0000000000000000000000000000000000000000000000000000000000000001" ); var blackKingLongRook = BigInt( "0b0000000000000000000000000000000000000000000000000000000010000000" ); var whiteKingShortRook = BigInt( "0b0000000100000000000000000000000000000000000000000000000000000000" ); var whiteKingLongRook = BigInt( "0b1000000000000000000000000000000000000000000000000000000000000000" ); var whitePawnLongGuards = BigInt( "0b0000000011100000000000000000000000000000000000000000000000000000" ); var whitePawnShortGuards = BigInt( "0b0000000000001110000000000000000000000000000000000000000000000000" ); var blackPawnLongGuards = BigInt( "0b0000000000000000000000000000000000000000000000001110000000000000" ); var blackPawnShortGuards = BigInt( "0b0000000000000000000000000000000000000000000000000000011100000000" ); var boardMapping = { a1: "0b1000000000000000000000000000000000000000000000000000000000000000", b1: "0b0100000000000000000000000000000000000000000000000000000000000000", c1: "0b0010000000000000000000000000000000000000000000000000000000000000", d1: "0b0001000000000000000000000000000000000000000000000000000000000000", e1: "0b0000100000000000000000000000000000000000000000000000000000000000", f1: "0b0000010000000000000000000000000000000000000000000000000000000000", g1: "0b0000001000000000000000000000000000000000000000000000000000000000", h1: "0b0000000100000000000000000000000000000000000000000000000000000000", a2: "0b0000000010000000000000000000000000000000000000000000000000000000", b2: "0b0000000001000000000000000000000000000000000000000000000000000000", c2: "0b0000000000100000000000000000000000000000000000000000000000000000", d2: "0b0000000000010000000000000000000000000000000000000000000000000000", e2: "0b0000000000001000000000000000000000000000000000000000000000000000", f2: "0b0000000000000100000000000000000000000000000000000000000000000000", g2: "0b0000000000000010000000000000000000000000000000000000000000000000", h2: "0b0000000000000001000000000000000000000000000000000000000000000000", a3: "0b0000000000000000100000000000000000000000000000000000000000000000", b3: "0b0000000000000000010000000000000000000000000000000000000000000000", c3: "0b0000000000000000001000000000000000000000000000000000000000000000", d3: "0b0000000000000000000100000000000000000000000000000000000000000000", e3: "0b0000000000000000000010000000000000000000000000000000000000000000", f3: "0b0000000000000000000001000000000000000000000000000000000000000000", g3: "0b0000000000000000000000100000000000000000000000000000000000000000", h3: "0b0000000000000000000000010000000000000000000000000000000000000000", a4: "0b0000000000000000000000001000000000000000000000000000000000000000", b4: "0b0000000000000000000000000100000000000000000000000000000000000000", c4: "0b0000000000000000000000000010000000000000000000000000000000000000", d4: "0b0000000000000000000000000001000000000000000000000000000000000000", e4: "0b0000000000000000000000000000100000000000000000000000000000000000", f4: "0b0000000000000000000000000000010000000000000000000000000000000000", g4: "0b0000000000000000000000000000001000000000000000000000000000000000", h4: "0b0000000000000000000000000000000100000000000000000000000000000000", a5: "0b0000000000000000000000000000000010000000000000000000000000000000", b5: "0b0000000000000000000000000000000001000000000000000000000000000000", c5: "0b0000000000000000000000000000000000100000000000000000000000000000", d5: "0b0000000000000000000000000000000000010000000000000000000000000000", e5: "0b0000000000000000000000000000000000001000000000000000000000000000", f5: "0b0000000000000000000000000000000000000100000000000000000000000000", g5: "0b0000000000000000000000000000000000000010000000000000000000000000", h5: "0b0000000000000000000000000000000000000001000000000000000000000000", a6: "0b0000000000000000000000000000000000000000100000000000000000000000", b6: "0b0000000000000000000000000000000000000000010000000000000000000000", c6: "0b0000000000000000000000000000000000000000001000000000000000000000", d6: "0b0000000000000000000000000000000000000000000100000000000000000000", e6: "0b0000000000000000000000000000000000000000000010000000000000000000", f6: "0b0000000000000000000000000000000000000000000001000000000000000000", g6: "0b0000000000000000000000000000000000000000000000100000000000000000", h6: "0b0000000000000000000000000000000000000000000000010000000000000000", a7: "0b0000000000000000000000000000000000000000000000001000000000000000", b7: "0b0000000000000000000000000000000000000000000000000100000000000000", c7: "0b0000000000000000000000000000000000000000000000000010000000000000", d7: "0b0000000000000000000000000000000000000000000000000001000000000000", e7: "0b0000000000000000000000000000000000000000000000000000100000000000", f7: "0b0000000000000000000000000000000000000000000000000000010000000000", g7: "0b0000000000000000000000000000000000000000000000000000001000000000", h7: "0b0000000000000000000000000000000000000000000000000000000100000000", a8: "0b0000000000000000000000000000000000000000000000000000000010000000", b8: "0b0000000000000000000000000000000000000000000000000000000001000000", c8: "0b0000000000000000000000000000000000000000000000000000000000100000", d8: "0b0000000000000000000000000000000000000000000000000000000000010000", e8: "0b0000000000000000000000000000000000000000000000000000000000001000", f8: "0b0000000000000000000000000000000000000000000000000000000000000100", g8: "0b0000000000000000000000000000000000000000000000000000000000000010", h8: "0b0000000000000000000000000000000000000000000000000000000000000001" }; BigInt.prototype.toJSON = function() { return this.toString(); }; // src/helpers/bitboards.ts function applyMove(bitBoard, from, to, pieceBitBoard) { let newBitBoard = { ...bitBoard }; const fromMask = BigInt(1) << BigInt(64 - from); const toMask = BigInt(1) << BigInt(64 - to); MultiLog( 3 /* info */, `apply move to ${bigIntToBinaryString(bitBoard[pieceBitBoard])} from ${from} to ${to} `, LoggerConfig.verbosity ); const fromMaskString = bigIntToBinaryString(fromMask); const toMaskString = bigIntToBinaryString(toMask); MultiLog(3 /* info */, `from mask ${fromMaskString}`, LoggerConfig.verbosity); MultiLog(3 /* info */, `to mask ${toMaskString}`, LoggerConfig.verbosity); newBitBoard = clearPosition(newBitBoard, to); newBitBoard[pieceBitBoard] = newBitBoard[pieceBitBoard] & ~fromMask | toMask; return newBitBoard; } function clearPosition(bitBoard, position) { const removalMask = binaryMask64(position, "all_ones_with_position_as_zero"); const removalMaskString = bigIntToBinaryString(removalMask); MultiLog(0 /* warn */, removalMaskString, LoggerConfig.verbosity); let newBitBoard = { ...bitBoard }; for (let piece in newBitBoard) { let pieceBoard = newBitBoard[piece]; const pieceBoardString = bigIntToBinaryString(pieceBoard); MultiLog(3 /* info */, `${piece} is ${pieceBoardString}`, LoggerConfig.verbosity); newBitBoard[piece] = pieceBoard & removalMask; } return newBitBoard; } function getBitBoardPosition(file, rank) { const fileNumber = files.indexOf(file); const minRank = (rank - 1) * 8; MultiLog( 3 /* info */, `position ${file}${rank} minrank: ${minRank} fileNumber: ${fileNumber} `, LoggerConfig.verbosity ); return minRank + fileNumber + 1; } function getFileAndRank(bitBoardPosition) { const zeroBasedPosition = bitBoardPosition - 1; const rank = Math.floor(zeroBasedPosition / 8) + 1; const fileIndex = zeroBasedPosition % 8; const file = files[fileIndex]; return { file, rank }; } function bigIntToBinaryString(inputNumber) { let binaryString = inputNumber.toString(2); const desiredWidth = 64; let paddedBinaryString = binaryString.padStart(desiredWidth, "0"); return paddedBinaryString; } function bitCount(bitboard) { let count = 0; for (let i = 0; i < 64; i++) { const checkBit = BigInt(1) << BigInt(i); if (bitboard & checkBit) { count += 1; } } return count; } function binaryMask64(position, maskType) { const binaryMask = BigInt(1) << BigInt(64 - position); if (maskType === "all_zeroes_with_position_as_one") { return binaryMask; } MultiLog(3 /* info */, bigIntToBinaryString(allOnes), LoggerConfig.verbosity); MultiLog(3 /* info */, bigIntToBinaryString(binaryMask), LoggerConfig.verbosity); return allOnes & ~binaryMask; } function occupiedBy(currentBoard, position) { const queryMask = binaryMask64(position, "all_zeroes_with_position_as_one"); for (let piece in currentBoard) { let pieceBoard = currentBoard[piece]; const foundPiece = pieceBoard & queryMask; if (foundPiece) { return piece; } } return null; } function isOccupied(currentBoard, position) { let compositePositions = allPositions(currentBoard); return isOccupiedComposite(compositePositions, position); } function isOccupiedComposite(compositePositions, position) { const queryMask = binaryMask64(position, "all_zeroes_with_position_as_one"); const foundPiece = compositePositions & queryMask; return !!foundPiece; } function allPositions(currentBoard) { let compositePositions = BigInt(0); for (let piece in currentBoard) { let pieceBoard = currentBoard[piece]; compositePositions = compositePositions | pieceBoard; } return compositePositions; } function allWhitePositions(currentBoard) { let compositePositions = BigInt(0); for (let piece in currentBoard) { if (piece.toLowerCase().includes("white")) { let pieceBoard = currentBoard[piece]; compositePositions = compositePositions | pieceBoard; } } return compositePositions; } function allBlackPositions(currentBoard) { let compositePositions = BigInt(0); for (let piece in currentBoard) { if (piece.toLowerCase().includes("black")) { let pieceBoard = currentBoard[piece]; compositePositions = compositePositions | pieceBoard; } } return compositePositions; } function getMoveFromBoardStates(before, after) { if (before.blackKing !== after.blackKing && before.blackRook !== after.blackRook || before.whiteKing !== after.whiteKing && before.whiteRook !== after.whiteRook) { return getCastledMoveFromBoardStates(before, after); } return getSinglePieceMoveFromBoardStates(before, after); } function getSinglePieceMoveFromBoardStates(before, after) { let move = { from: 0, to: 0, piece: "none", pieceTaken: "none", score: 0, evaluations: 0, castleRookFrom: 0, castleRookTo: 0 }; for (const piece of Object.keys(before)) { if (piece === "none") continue; const beforeBitboard = before[piece]; const afterBitboard = after[piece]; const pieceCountBefore = bitCount(beforeBitboard); const pieceCountAfter = bitCount(afterBitboard); if (pieceCountBefore > pieceCountAfter) { move.pieceTaken = piece; } else { if (beforeBitboard !== afterBitboard) { const movedFromBitboard = beforeBitboard & ~afterBitboard; const movedToBitboard = afterBitboard & ~beforeBitboard; if (movedFromBitboard) { move.from = findBitPositionReverse(movedFromBitboard); move.piece = piece; } if (movedToBitboard) { move.to = findBitPositionReverse(movedToBitboard); } } } } if (move.piece === "whitePawn") { if (move.to - move.from !== 8 && move.to - move.from !== 16 && move.pieceTaken === "none") { move.pieceTaken = "blackPawn"; } } if (move.piece === "blackPawn") { if (move.from - move.to !== 8 && move.from - move.to !== 16 && move.pieceTaken === "none") { move.pieceTaken = "whitePawn"; } } return move; } function getBeforeAndAfterPositions(before, after) { let beforePosition = 0, afterPosition = 0; if (before !== after) { const movedFromBitboard = before & ~after; const movedToBitboard = after & ~before; if (movedFromBitboard) { beforePosition = findBitPositionReverse(movedFromBitboard); } if (movedToBitboard) { afterPosition = findBitPositionReverse(movedToBitboard); } } return [beforePosition, afterPosition]; } function getCastledMoveFromBoardStates(before, after) { let move = { from: 0, to: 0, piece: "none", pieceTaken: "none", score: 0, evaluations: 0, castleRookFrom: 0, castleRookTo: 0 }; if (before.blackKing !== after.blackKing && before.blackRook !== after.blackRook) { move.piece = "blackKing"; const blackKingNewPosition = findBitPosition(after.blackKing); move.from = 61; move.to = blackKingNewPosition ? blackKingNewPosition : 0; const [beforeRook, afterRook] = getBeforeAndAfterPositions(before.blackRook, after.blackRook); move.castleRookFrom = beforeRook; move.castleRookTo = afterRook; } if (before.whiteKing !== after.whiteKing && before.whiteRook !== after.whiteRook) { move.piece = "whiteKing"; const whiteKingNewPosition = findBitPosition(after.whiteKing); move.from = 5; move.to = whiteKingNewPosition ? whiteKingNewPosition : 0; const [beforeRook, afterRook] = getBeforeAndAfterPositions(before.whiteRook, after.whiteRook); move.castleRookFrom = beforeRook; move.castleRookTo = afterRook; } return move; } function findBitPositionReverse(bitboard) { let position = 63; let mask = BigInt(1) << BigInt(63); for (let i = 0; i < 64; i++) { if ((bitboard & mask) !== BigInt(0)) { position = i; break; } mask = mask >> BigInt(1); } return position + 1; } function findBitPositions(bitboard) { let positionArray = []; let position = 63; let mask = BigInt(1) << BigInt(63); for (let i = 0; i < 64; i++) { if ((bitboard & mask) !== BigInt(0)) { position = i; positionArray.push(position + 1); } mask = mask >> BigInt(1); } return positionArray; } function findBitPosition(bitboard) { let position = 63; let mask = BigInt(1) << BigInt(63); for (let i = 0; i < 64; i++) { if ((bitboard & mask) !== BigInt(0)) { position = i; return position + 1; } mask = mask >> BigInt(1); } } function isAtoHwraparound(fromPosition, toPosition) { const { file: fromFile } = getFileAndRank(fromPosition); const { file: toFile } = getFileAndRank(toPosition); return (fromFile + toFile).includes("a") && (fromFile + toFile).includes("h"); } function isABCtoFGHwraparound(fromPosition, toPosition) { const { file: fromFile } = getFileAndRank(fromPosition); const { file: toFile } = getFileAndRank(toPosition); let leftSideFile = false; if ((fromFile + toFile).includes("a") || (fromFile + toFile).includes("b") || (fromFile + toFile).includes("c")) { leftSideFile = true; } let rightSideFile = false; if ((fromFile + toFile).includes("f") || (fromFile + toFile).includes("g") || (fromFile + toFile).includes("h")) { rightSideFile = true; } return leftSideFile && rightSideFile; } function bitBoardsReadable(bitBoard) { return { whitePawn: bigIntToBinaryString(bitBoard.whitePawn), whiteKnight: bigIntToBinaryString(bitBoard.whiteKnight), whiteBishop: bigIntToBinaryString(bitBoard.whiteBishop), whiteRook: bigIntToBinaryString(bitBoard.whiteRook), whiteQueen: bigIntToBinaryString(bitBoard.whiteQueen), whiteKing: bigIntToBinaryString(bitBoard.whiteKing), blackPawn: bigIntToBinaryString(bitBoard.blackPawn), blackKnight: bigIntToBinaryString(bitBoard.blackKnight), blackBishop: bigIntToBinaryString(bitBoard.blackBishop), blackRook: bigIntToBinaryString(bitBoard.blackRook), blackQueen: bigIntToBinaryString(bitBoard.blackQueen), blackKing: bigIntToBinaryString(bitBoard.blackKing), none: bigIntToBinaryString(bitBoard.none) }; } function isShortCastleRouteBlocked(board, isWhitesTurn, enemyControlledSquares) { const compositePositions = allPositions(board) | enemyControlledSquares; return !!(compositePositions & (isWhitesTurn ? whiteKingShortCastleRoute : blackKingShortCastleRoute)); } function isLongCastleRouteBlocked(board, isWhitesTurn, enemyControlledSquares) { const compositePositions = allPositions(board) | enemyControlledSquares; const pathBlockingPositions = isWhitesTurn ? whiteKingLongCastleRoute : blackKingLongCastleRoute; return !!(compositePositions & pathBlockingPositions); } // src/referee/mockBoardStates.ts var MiddleGameBoard = { whitePawn: BigInt("0b0000000000001000000000011110011000000000000000000000000000000000"), whiteKnight: BigInt("0b0000001000000000010000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0010010000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000010100110000000010100000000000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000100000000000000000000010"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000100100"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000001"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var EndGameBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000001"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var MateInOneForWhiteGameBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b0100001000000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0000000000100000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000000001"), none: BigInt(0) }; var MateInOneForBlackGameBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000001"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var BlackShortCastledGameBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000000000011100000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000100"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: blackKingShortCastleDestination, none: BigInt(0) }; var BlackLongCastledGameBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000001110000000000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000000010001"), blackQueen: BigInt(0), blackKing: blackKingLongCastleDestination, none: BigInt(0) }; var CastleForBlackGameBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000000000011100000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000000000001"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var CastleForBlackGameLongBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000000000011100000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000000"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var CastleForBlackAfterGameBoard = { whitePawn: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000000000000000000000000011100000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000000000"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000100"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000000010"), none: BigInt(0) }; var DuellingPawnsBoard = { whitePawn: BigInt("0b0000000000000000000000001111111100000000000000000000000000000000"), whiteKnight: BigInt("0b0100001000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0010010000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000011111111000000000000000000000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000001000010"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000100100"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000001"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var BlackAdvantageBoard = { whitePawn: BigInt("0b0000000000000000000000001110011100000000000000000000000000000000"), whiteKnight: BigInt("0b0100001000000000000000000000000000000000000000000000000000000000"), whiteBishop: BigInt("0b0010010000000000000000000000000000000000000000000000000000000000"), whiteRook: BigInt("0b1000000100000000000000000000000000000000000000000000000000000000"), whiteQueen: BigInt("0b0001000000000000000000000000000000000000000000000000000000000000"), whiteKing: BigInt("0b0000100000000000000000000000000000000000000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000000000011111111000000000000000000000000"), blackKnight: BigInt("0b0000000000000000000000000000000000000000000000000000000001000010"), blackBishop: BigInt("0b0000000000000000000000000000000000000000000000000000000000100100"), blackRook: BigInt("0b0000000000000000000000000000000000000000000000000000000010000001"), blackQueen: BigInt("0b0000000000000000000000000000000000000000000000000000000000010000"), blackKing: BigInt("0b0000000000000000000000000000000000000000000000000000000000001000"), none: BigInt(0) }; var MiniMaxTestBoardOne = { whitePawn: BigInt("0b0000000000000000000000000000000000010000001000000000000000000000"), whiteKnight: BigInt(0), whiteBishop: BigInt(0), whiteRook: BigInt(0), whiteQueen: BigInt(0), whiteKing: BigInt(0), blackPawn: BigInt("0b0000000000000000000000000000000000000000000010000001000000000000"), blackKnight: BigInt(0), blackBishop: BigInt(0), blackRook: BigInt(0), blackQueen: BigInt(0), blackKing: BigInt(0), none: BigInt(0) }; var whitePawnChain_Pyramid = BigInt( "0b0000000010000000010000010010001000010100000010000000000000000000" ); var whitePawnChain_ThreeIslands = BigInt( "0b0000000010010010010010010000000000000000000000000000000000000000" ); var whitePawnChain_NoChains = BigInt( "0b0000000010101010000000000101010100000000000000000000000000000000" ); var blackPawnChain_Pyramid = BigInt( "0b0000000000000000000010000001010000100010010000011000000000000000" ); var blackPawnChain_ThreeIslands = BigInt( "0b0000000000000000000000000000000000000000100100100100100100000000" ); var blackPawnChain_NoChains = BigInt( "0b0000000000000000000000000000000001010101000000001010101000000000" ); var EnPassantBoard = { whitePawn: BigInt("0b0000000000111111000000001000000000001010000000000000000000000000"), blackPawn: BigInt("0b0000000000000000000000000101000000000100000000000000000100000000"), whiteKnight: BigInt(0), whiteBishop: BigInt(0), whiteRook: BigInt(0), whiteQueen: BigInt(0), whiteKing: BigInt(0), blackKnight: BigInt(0), blackBishop: BigInt(0), blackRook: BigInt(0), blackQueen: BigInt(0), blackKing: BigInt(0), none: BigInt(0) }; // src/helpers/boardevaluation/boardEval.ts function evaluateBoard(currentBoard, evaluateForWhite) { let score = 0; score += evaluateMaterialAdvantages(currentBoard, evaluateForWhite); score += evaluatePositionalAdvantages(currentBoard, evaluateForWhite); score += evaluatePromotionalPossibilities( evaluateForWhite ? currentBoard.whitePawn : currentBoard.blackPawn, evaluateForWhite ); score += evaluatePawnChains( evaluateForWhite ? currentBoard.whitePawn : currentBoard.blackPawn, evaluateForWhite ); score += evaluatePieceDevelopment(currentBoard, evaluateForWhite); score += evaluateFreedomToMove(currentBoard, evaluateForWhite); score += evaluateKingSafety(currentBoard, evaluateForWhite); return score; } function evaluateMaterialAdvantages(currentBoard, evaluateForWhite) { let whiteScore = 0, blackScore = 0; whiteScore += bitCount(currentBoard.whitePawn) * pieceValues.pawn; blackScore += bitCount(currentBoard.blackPawn) * pieceValues.pawn; whiteScore += bitCount(currentBoard.whiteRook) * pieceValues.rook; blackScore += bitCount(currentBoard.blackRook) * pieceValues.rook; whiteScore += bitCount(currentBoard.whiteKnight) * pieceValues.knight; blackScore += bitCount(currentBoard.blackKnight) * pieceValues.knight; whiteScore += bitCount(currentBoard.whiteBishop) * pieceValues.bishop; blackScore += bitCount(currentBoard.blackBishop) * pieceValues.bishop; whiteScore += bitCount(currentBoard.whiteQueen) * pieceValues.queen; blackScore += bitCount(currentBoard.blackQueen) * pieceValues.queen; if (evaluateForWhite) { return whiteScore - blackScore; } return blackScore - whiteScore; } function evaluatePositionalAdvantages(currentBoard, evaluateForWhite) { let whiteScore = 0, blackScore = 0; whiteScore += evaluateCentralDominanceAdvantages( currentBoard.whitePawn, evaluateForWhite, "whitePawn" ); blackScore += evaluateCentralDominanceAdvantages( currentBoard.blackPawn, evaluateForWhite, "blackPawn" ); if (evaluateForWhite) { return whiteScore - blackScore; } return blackScore - whiteScore; } function evaluateCentralDominanceAdvantages(pieceBitBoard, evaluateForWhite, piece) { let score = 0; const evalAbsoluteCentre = CentralDominanceWeightings.absoluteCentre & pieceBitBoard; score += bitCount(evalAbsoluteCentre) * EvalWeightings.absoluteCentreWeight; const evalInnerRing = CentralDominanceWeightings.innerRing & pieceBitBoard; score += bitCount(evalInnerRing) * EvalWeightings.innerRingWeight; const evalOuterRing = CentralDominanceWeightings.outerRing & pieceBitBoard; score += bitCount(evalOuterRing) * EvalWeightings.outerRingWeight; return score; } function evaluatePromotionalPossibilities(pawnBitBoard, evaluateForWhite) { let score = 0; if (evaluateForWhite) { const evalSeventhRankPawns = RankWeightings.seventhRank & pawnBitBoard; return bitCount(evalSeventhRankPawns) * EvalWeightings.oneMoveUntilPromotionWeight; } const evalSecondRankPawns = RankWeightings.secondRank & pawnBitBoard; return bitCount(evalSecondRankPawns) * EvalWeightings.oneMoveUntilPromotionWeight; } function evaluatePawnChains(pawnBitBoard, evaluateForWhite) { let rightDiagonalShift, leftDiagonalShift; if (evaluateForWhite) { rightDiagonalShift = (pawnBitBoard & aTogFilesOnly) >> BigInt(7); leftDiagonalShift = (pawnBitBoard & bTohFilesOnly) >> BigInt(9); } else { rightDiagonalShift = (pawnBitBoard & bTohFilesOnly) << BigInt(7); leftDiagonalShift = (pawnBitBoard & aTogFilesOnly) << BigInt(9); } const rightChainPawns = rightDiagonalShift & pawnBitBoard; const leftChainPawns = leftDiagonalShift & pawnBitBoard; const rightChainCount = bitCount(rightChainPawns); const leftChainCount = bitCount(leftChainPawns); return (rightChainCount + leftChainCount) * EvalWeightings.pawnChainWeight; } function evaluatePieceDevelopment(currentBoard, evaluateForWhite) { let developmentScore = 0; const startingKnights = evaluateForWhite ? StartingBoard.whiteKnight : StartingBoard.blackKnight; const currentKnights = evaluateForWhite ? currentBoard.whiteKnight : currentBoard.blackKnight; const everywhereButStartingPositionsForKnights = ~startingKnights; const movedKnightPositions = currentKnights & everywhereButStartingPositionsForKnights; const movedKnightCount = bitCount(movedKnightPositions); developmentScore += movedKnightCount * EvalWeightings.developedBishopKnight; const startingBishops = evaluateForWhite ? StartingBoard.whiteBishop : StartingBoard.blackBishop; const currentBishops = evaluateForWhite ? currentBoard.whiteBishop : currentBoard.blackBishop; const everywhereButStartingPositionsForBishops = ~startingBishops; const movedBishopPositions = currentBishops & everywhereButStartingPositionsForBishops; const movedBishopCount = bitCount(movedBishopPositions); developmentScore += movedBishopCount * EvalWeightings.developedBishopKnight; const startingRooks = evaluateForWhite ? StartingBoard.whiteRook : StartingBoard.blackRook; const currentRooks = evaluateForWhite ? currentBoard.whiteRook : currentBoard.blackRook; const everywhereButStartingPositionsForRooks = ~startingRooks; const movedRookPositions = currentRooks & everywhereButStartingPositionsForRooks; const movedRookCount = bitCount(movedRookPositions); developmentScore += movedRookCount * EvalWeightings.developedRook; return developmentScore; } function evaluateFreedomToMove(currentBoard, evaluateForWhite) { let freedomToMove = 0; const friendlyPieces = evaluateForWhite ? allWhitePositions(currentBoard) : allBlackPositions(currentBoard); const enemyPieces = evaluateForWhite ? allBlackPositions(currentBoard) : allWhitePositions(currentBoard); const knightMoves = AllKnightMoves(currentBoard, friendlyPieces, evaluateForWhite); const bishopMoves = AllBishopMoves(currentBoard, friendlyPieces, enemyPieces, evaluateForWhite); const rookMoves = AllRookMoves(currentBoard, friendlyPieces, enemyPieces, evaluateForWhite); const queenMoves = AllQueenMoves(currentBoard, friendlyPieces, enemyPieces, evaluateForWhite); const kingMoves = AllKingMoves(currentBoard, friendlyPieces, evaluateForWhite); const pawnMoves = evaluateForWhite ? AllBlackPawnMovesComposite(currentBoard).blackPawn : AllWhitePawnMovesComposite(currentBoard).whitePawn; freedomToMove += EvalWeightings.freedomToMove * bitCount(knightMoves); freedomToMove += EvalWeightings.freedomToMove * bitCount(bishopMoves); freedomToMove += EvalWeightings.freedomToMove * bitCount(rookMoves); freedomToMove += EvalWeightings.freedomToMove * bitCount(queenMoves); freedomToMove += EvalWeightings.freedomToMove * bitCount(kingMoves); freedomToMove += EvalWeightings.freedomToMove * bitCount(pawnMoves); return freedomToMove; } function evaluateSquareControl(currentBoard, evaluateForWhite) { let controlledSquares = BigInt(0); const friendlyPieces = evaluateForWhite ? allWhitePositions(currentBoard) : allBlackPositions(currentBoard); const enemyPieces = evaluateForWhite ? allBlackPositions(currentBoard) : allWhitePositions(currentBoard); const knightMoves = AllKnightMoves(currentBoard, friendlyPieces, evaluateForWhite); const bishopMoves = AllBishopMoves(currentBoard, friendlyPieces, enemyPieces, evaluateForWhite); const rookMoves = AllRookMoves(currentBoard, friendlyPieces, enemyPieces, evaluateForWhite); const queenMoves = AllQueenMoves(currentBoard, friendlyPieces, enemyPieces, evaluateForWhite); const kingMoves = AllKingMoves(currentBoard, friendlyPieces, evaluateForWhite); const pawnMoves = evaluateForWhite ? AllWhitePawnCaptures(currentBoard, allOnes) : AllBlackPawnCaptures(currentBoard, allOnes); controlledSquares |= knightMoves; controlledSquares |= bishopMoves; controlledSquares |= rookMoves; controlledSquares |= queenMoves; controlledSquares |= kingMoves; controlledSquares |= pawnMoves; return controlledSquares; } function evaluateKingSafety(currentBoard, evaluateForWhite) { if (evaluateForWhite) { return 0; } else { const blackKingIsLong = !!(currentBoard.blackKing & blackKingLongCastleDestination); const blackPawnsProtectLong = (currentBoard.blackPawn & blackPawnLongGuards) === blackPawnLongGuards; const blackRookHasCastledLong = !!(currentBoard.blackRook & blackKingLongCastleRookDestination); if (blackKingIsLong && blackPawnsProtectLong && blackRookHasCastledLong) { return EvalWeightings.safeKing; } const blackKingIsShort = !!(currentBoard.blackKing & blackKingShortCastleDestination); const blackPawnsProtectShort = (currentBoard.blackPawn & blackPawnShortGuards) === blackPawnShortGuards; const blackRookHasCastledShort = !!(currentBoard.blackRook & blackKingShortCastleRookDestination); if (blackKingIsShort && blackPawnsProtectShort && blackRookHasCastledShort) { return EvalWeightings.safeKing; } } return 0; } // src/helpers/search/nodes/bishops/bishopNodes.ts function bishopNodes(node, evalLogs) { let possibleNodes = []; const isWhitesTurn = node.gameState.isWhitesTurn; const bishopsToMove = isWhitesTurn ? node.boardState.whiteBishop : node.boardState.blackBishop; const bishopPositions = findBitPositions(bishopsToMove); const allFriendlyOccupiedPositions = isWhitesTurn ? allWhitePositions(node.boardState) : allBlackPositions(node.boardState); const allEnemyOccupiedPositions = isWhitesTurn ? allBlackPositions(node.boardState) : allWhitePositions(node.boardState); bishopPositions.forEach((bishopPosition) => { const offsets = diagonalOffsets; offsets.forEach((offset) => { let lastPosition = bishopPosition; for (let newPosition = bishopPosition + offset; newPosition >= 1 && newPosition <= 64; newPosition += offset) { if (isABCtoFGHwraparound(lastPosition, newPosition)) { break; } if (isOccupiedComposite(allFriendlyOccupiedPositions, newPosition)) { break; } if (!isOccupiedComposite(allFriendlyOccupiedPositions, newPosition)) { const newBoardState = applyMove( node.boardState, bishopPosition, newPosition, isWhitesTurn ? "whiteBishop" : "blackBishop" ); possibleNodes = pushNewNode( possibleNodes, node, newBoardState, evalLogs, 0 ); } lastPosition = newPosition; if (isOccupiedComposite(allEnemyOccupiedPositions, newPosition)) { break; } } });