kokopu
Version:
A JavaScript/TypeScript library implementing the chess game rules and providing tools to read/write the standard chess file formats.
111 lines • 5.81 kB
JavaScript
;
/*!
* -------------------------------------------------------------------------- *
* *
* 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.getUCINotation = getUCINotation;
exports.parseUCINotation = parseUCINotation;
const base_types_impl_1 = require("./base_types_impl");
const fen_1 = require("./fen");
const legality_1 = require("./legality");
const move_generation_1 = require("./move_generation");
const exception_1 = require("../exception");
const i18n_1 = require("../i18n");
/**
* Convert the given move descriptor to UCI notation.
*/
function getUCINotation(position, descriptor, forceKxR) {
let result = descriptor.from();
if (descriptor.isCastling()) {
result += forceKxR || position.variant === 1 /* GameVariantImpl.CHESS960 */ ? descriptor.rookFrom() : descriptor.to();
}
else {
result += descriptor.to();
}
if (descriptor.isPromotion()) {
result += descriptor.promotion();
}
return result;
}
/**
* Parse a UCI notation for the given position.
*/
function parseUCINotation(position, notation, strict) {
// General syntax
const m = /^([a-h][1-8])([a-h][1-8])([kqrbnp]?)$/.exec(notation);
if (m === null) {
throw new exception_1.InvalidNotation((0, fen_1.getFEN)(position), notation, i18n_1.i18n.INVALID_UCI_NOTATION_SYNTAX);
}
// Ensure that the position is legal (this is also done in `moveGeneration.isMoveLegal(..)`, but performing this check beforehand
// allows to fill the exception with an error message that is more explicit).
if (!(0, legality_1.isLegal)(position)) {
throw new exception_1.InvalidNotation((0, fen_1.getFEN)(position), notation, i18n_1.i18n.ILLEGAL_POSITION);
}
// m[1] - from
// m[2] - to
// m[3] - promotion piece
const from = (0, base_types_impl_1.squareFromString)(m[1]);
let to = (0, base_types_impl_1.squareFromString)(m[2]);
let kxRSubstitutionApplied = false;
let expectedRookFrom = -1; // >= 0 only if KxR substitution has been applied.
// For non-Chess960 variants, if KxR is detected (and allowed), replace the given `to` square
// by the actual destination square of the king.
if (position.variant !== 1 /* GameVariantImpl.CHESS960 */ && !strict && position.board[from] !== -1 /* SpI.EMPTY */ && position.board[to] !== -1 /* SpI.EMPTY */ &&
position.board[from] % 2 === position.board[to] % 2) {
const fromPiece = Math.trunc(position.board[from] / 2);
const toPiece = Math.trunc(position.board[to] / 2);
if (fromPiece === 0 /* PieceImpl.KING */ && toPiece === 2 /* PieceImpl.ROOK */) {
kxRSubstitutionApplied = true;
expectedRookFrom = to;
to = position.turn * 112 + (from < to ? 6 : 2);
}
}
// Perform move analysis.
const candidate = (0, move_generation_1.isMoveLegal)(position, from, to);
let result;
// No legal move.
if (!candidate) {
throw new exception_1.InvalidNotation((0, fen_1.getFEN)(position), notation, i18n_1.i18n.ILLEGAL_UCI_MOVE);
}
// Manage promotion.
if (candidate.type === 'promotion') {
if (m[3] === '') {
throw new exception_1.InvalidNotation((0, fen_1.getFEN)(position), notation, i18n_1.i18n.ILLEGAL_UCI_MOVE);
}
result = candidate.moveDescriptorFactory((0, base_types_impl_1.pieceFromString)(m[3]));
if (!result) {
throw new exception_1.InvalidNotation((0, fen_1.getFEN)(position), notation, i18n_1.i18n.ILLEGAL_UCI_MOVE);
}
}
else {
if (m[3] !== '') { // Throw if a promotion piece is provided while no promotion happens.
throw new exception_1.InvalidNotation((0, fen_1.getFEN)(position), notation, i18n_1.i18n.ILLEGAL_UCI_MOVE);
}
result = candidate.moveDescriptor;
}
// Check that the KxR substitution is valid if it has been applied.
if (kxRSubstitutionApplied && (!result.isCastling() || expectedRookFrom !== result._optionalSquare1)) {
throw new exception_1.InvalidNotation((0, fen_1.getFEN)(position), notation, i18n_1.i18n.ILLEGAL_UCI_MOVE);
}
return result;
}
//# sourceMappingURL=uci.js.map