UNPKG

kokopu

Version:

A JavaScript/TypeScript library implementing the chess game rules and providing tools to read/write the standard chess file formats.

244 lines 17.6 kB
"use strict"; /*! * -------------------------------------------------------------------------- * * * * Kokopu - A JavaScript/TypeScript chess library. * * <https://www.npmjs.com/package/kokopu> * * Copyright (C) 2018-2026 Yoann Le Montagner <yo35 -at- melix.net> * * * * Kokopu is free software: you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version. * * * * Kokopu is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General * * Public License along with this program. If not, see * * <http://www.gnu.org/licenses/>. * * * * -------------------------------------------------------------------------- */ Object.defineProperty(exports, "__esModule", { value: true }); exports.hasCanonicalStartPosition = hasCanonicalStartPosition; exports.makeEmpty = makeEmpty; exports.makeInitial = makeInitial; exports.make960FromScharnagl = make960FromScharnagl; exports.makeCopy = makeCopy; const EMPTY_BOARD = [ -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, ]; const REGULAR_START_BOARD = [ 4 /* CpI.WR */, 8 /* CpI.WN */, 6 /* CpI.WB */, 2 /* CpI.WQ */, 0 /* CpI.WK */, 6 /* CpI.WB */, 8 /* CpI.WN */, 4 /* CpI.WR */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 5 /* CpI.BR */, 9 /* CpI.BN */, 7 /* CpI.BB */, 3 /* CpI.BQ */, 1 /* CpI.BK */, 7 /* CpI.BB */, 9 /* CpI.BN */, 5 /* CpI.BR */, /* eslint-enable */ ]; const HORDE_START_BOARD = [ 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, 10 /* CpI.WP */, 10 /* CpI.WP */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, 10 /* CpI.WP */, 10 /* CpI.WP */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 5 /* CpI.BR */, 9 /* CpI.BN */, 7 /* CpI.BB */, 3 /* CpI.BQ */, 1 /* CpI.BK */, 7 /* CpI.BB */, 9 /* CpI.BN */, 5 /* CpI.BR */, /* eslint-enable */ ]; const START_POSITION_INFO = [ { board: REGULAR_START_BOARD, castling: [129 /* (1 << A-file) | (1 << H-file) */, 129 /* (1 << A-file) | (1 << H-file) */], king: [4 /* SquareImpl.E1 */, 116 /* SquareImpl.E8 */], }, null, // Chess960 null, // no king null, // white king only null, // black king only { board: REGULAR_START_BOARD, castling: [0, 0], king: [-1, -1], }, { board: HORDE_START_BOARD, castling: [0, 129 /* (1 << A-file) | (1 << H-file) */], king: [-1, 116 /* SquareImpl.E8 */], }, ]; function hasCanonicalStartPosition(variant) { return START_POSITION_INFO[variant] !== null; } function makeEmpty(variant) { return { board: EMPTY_BOARD.slice(), turn: 0 /* ColorImpl.WHITE */, castling: [0, 0], enPassant: -1, variant: variant, legal: variant === 2 /* GameVariantImpl.NO_KING */, king: [-1, -1], effectiveCastling: [0, 0], effectiveEnPassant: -1, }; } /** * @param variant - Must be a variant with a canonical start position. */ function makeInitial(variant) { const info = START_POSITION_INFO[variant]; // WARNING: applicable only to variants with a canonical start position. return { board: info.board.slice(), turn: 0 /* ColorImpl.WHITE */, castling: info.castling.slice(), enPassant: -1, variant: variant, legal: true, king: info.king.slice(), effectiveCastling: info.castling.slice(), effectiveEnPassant: -1, }; } /** * Chess960 initial position, following the numbering scheme proposed by Reinhard Scharnagl (see for instance https://chess960.net/start-positions/). * * @param scharnaglCode - Integer between 0 and 959 inclusive. */ function make960FromScharnagl(scharnaglCode) { const info = decodeScharnagl(scharnaglCode); const rank1 = info.pieceScheme.map(piece => piece * 2 + 0 /* ColorImpl.WHITE */); const rank8 = info.pieceScheme.map(piece => piece * 2 + 1 /* ColorImpl.BLACK */); return { board: [ /* eslint-disable @stylistic/comma-spacing, @stylistic/no-multi-spaces */ rank1[0], rank1[1], rank1[2], rank1[3], rank1[4], rank1[5], rank1[6], rank1[7], -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, 10 /* CpI.WP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -1 /* SpI.EMPTY */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, 11 /* CpI.BP */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, -2 /* SpI.INVALID */, rank8[0], rank8[1], rank8[2], rank8[3], rank8[4], rank8[5], rank8[6], rank8[7], /* eslint-enable */ ], turn: 0 /* ColorImpl.WHITE */, castling: [info.castling, info.castling], enPassant: -1, variant: 1 /* GameVariantImpl.CHESS960 */, legal: true, king: [0 /* SquareImpl.A1 */ + info.kingFile, 112 /* SquareImpl.A8 */ + info.kingFile], effectiveCastling: [info.castling, info.castling], effectiveEnPassant: -1, }; } /** * @param scharnaglCode - Integer between 0 and 959 inclusive. */ function decodeScharnagl(scharnaglCode) { const scheme = [-1, -1, -1, -1, -1, -1, -1, -1]; let castling = 0; let kingFile = -1; function forEachEmpty(fun) { let emptyIndex = 0; for (let file = 0; file < 8; ++file) { if (scheme[file] >= 0) { continue; } fun(file, emptyIndex); ++emptyIndex; } } function setAt(piece, emptyIndexTarget1, emptyIndexTarget2) { forEachEmpty((file, emptyIndex) => { if (emptyIndex === emptyIndexTarget1 || emptyIndex === emptyIndexTarget2) { scheme[file] = piece; } }); } // Light-square bishop scheme[(scharnaglCode % 4) * 2 + 1] = 3 /* PieceImpl.BISHOP */; scharnaglCode = Math.trunc(scharnaglCode / 4); // Dark-square bishop scheme[(scharnaglCode % 4) * 2] = 3 /* PieceImpl.BISHOP */; scharnaglCode = Math.trunc(scharnaglCode / 4); // Queen setAt(1 /* PieceImpl.QUEEN */, scharnaglCode % 6, -1); scharnaglCode = Math.trunc(scharnaglCode / 6); // Knights switch (scharnaglCode) { // `scharnaglCode` is guaranteed here to be between 0 and 9 inclusive case 0: setAt(4 /* PieceImpl.KNIGHT */, 0, 1); break; case 1: setAt(4 /* PieceImpl.KNIGHT */, 0, 2); break; case 2: setAt(4 /* PieceImpl.KNIGHT */, 0, 3); break; case 3: setAt(4 /* PieceImpl.KNIGHT */, 0, 4); break; case 4: setAt(4 /* PieceImpl.KNIGHT */, 1, 2); break; case 5: setAt(4 /* PieceImpl.KNIGHT */, 1, 3); break; case 6: setAt(4 /* PieceImpl.KNIGHT */, 1, 4); break; case 7: setAt(4 /* PieceImpl.KNIGHT */, 2, 3); break; case 8: setAt(4 /* PieceImpl.KNIGHT */, 2, 4); break; case 9: setAt(4 /* PieceImpl.KNIGHT */, 3, 4); break; } // Rooks and king forEachEmpty((file, emptyIndex) => { if (emptyIndex === 1) { scheme[file] = 0 /* PieceImpl.KING */; kingFile = file; } else { scheme[file] = 2 /* PieceImpl.ROOK */; castling |= 1 << file; } }); return { pieceScheme: scheme, castling: castling, kingFile: kingFile, }; } function makeCopy(position) { return { board: position.board.slice(), turn: position.turn, castling: position.castling.slice(), enPassant: position.enPassant, variant: position.variant, legal: position.legal, king: position.king.slice(), effectiveCastling: position.effectiveCastling === null ? null : position.effectiveCastling.slice(), effectiveEnPassant: position.effectiveEnPassant, }; } //# sourceMappingURL=impl.js.map