UNPKG

kokopu

Version:

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

142 lines (123 loc) 6.21 kB
/*! * -------------------------------------------------------------------------- * * * * Kokopu - A JavaScript/TypeScript chess library. * * <https://www.npmjs.com/package/kokopu> * * Copyright (C) 2018-2025 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/>. * * * * -------------------------------------------------------------------------- */ import { PieceImpl, SpI } from './base_types_impl'; import { PositionImpl } from './impl'; /** * Attack directions per colored piece. */ export const ATTACK_DIRECTIONS = [ [ -17, -16, -15, -1, 1, 15, 16, 17 ], // king/queen [ -17, -16, -15, -1, 1, 15, 16, 17 ], // king/queen [ -17, -16, -15, -1, 1, 15, 16, 17 ], // king/queen [ -17, -16, -15, -1, 1, 15, 16, 17 ], // king/queen [ -16, -1, 1, 16 ], // rook [ -16, -1, 1, 16 ], // rook [ -17, -15, 15, 17 ], // bishop [ -17, -15, 15, 17 ], // bishop [ -33, -31, -18, -14, 14, 18, 31, 33 ], // knight [ -33, -31, -18, -14, 14, 18, 31, 33 ], // knight [ 15, 17 ], // white pawn [ -17, -15 ], // black pawn ]; // ----------------------------------------------------------------------------- // isAttacked // ----------------------------------------------------------------------------- /** * Check if any piece of the given color attacks a given square. */ export function isAttacked(position: PositionImpl, square: number, attackerColor: number) { return isAttackedByNonSliding(position, square, PieceImpl.KING * 2 + attackerColor) || isAttackedByNonSliding(position, square, PieceImpl.KNIGHT * 2 + attackerColor) || isAttackedByNonSliding(position, square, PieceImpl.PAWN * 2 + attackerColor) || isAttackedBySliding(position, square, PieceImpl.ROOK * 2 + attackerColor, PieceImpl.QUEEN * 2 + attackerColor) || isAttackedBySliding(position, square, PieceImpl.BISHOP * 2 + attackerColor, PieceImpl.QUEEN * 2 + attackerColor); } function isAttackedByNonSliding(position: PositionImpl, square: number, nonSlidingAttacker: number) { for (const attackDirection of ATTACK_DIRECTIONS[nonSlidingAttacker]) { const sq = square - attackDirection; if ((sq & 0x88) === 0 && position.board[sq] === nonSlidingAttacker) { return true; } } return false; } function isAttackedBySliding(position: PositionImpl, square: number, slidingAttacker: number, queenAttacker: number) { for (const attackDirection of ATTACK_DIRECTIONS[slidingAttacker]) { let sq = square; while (true) { sq -= attackDirection; if ((sq & 0x88) === 0) { const cp = position.board[sq]; if (cp === SpI.EMPTY) { continue; } else if (cp === slidingAttacker || cp === queenAttacker) { return true; } } break; } } return false; } // ----------------------------------------------------------------------------- // getAttacks // ----------------------------------------------------------------------------- /** * Return the squares from which a piece of the given color attacks a given square. */ export function getAttacks(position: PositionImpl, square: number, attackerColor: number) { const result: number[] = []; findNonSlidingAttacks(position, square, result, PieceImpl.KING * 2 + attackerColor); findNonSlidingAttacks(position, square, result, PieceImpl.KNIGHT * 2 + attackerColor); findNonSlidingAttacks(position, square, result, PieceImpl.PAWN * 2 + attackerColor); findSlidingAttacks(position, square, result, PieceImpl.ROOK * 2 + attackerColor, PieceImpl.QUEEN * 2 + attackerColor); findSlidingAttacks(position, square, result, PieceImpl.BISHOP * 2 + attackerColor, PieceImpl.QUEEN * 2 + attackerColor); return result; } function findNonSlidingAttacks(position: PositionImpl, square: number, result: number[], nonSlidingAttacker: number) { for (const attackDirection of ATTACK_DIRECTIONS[nonSlidingAttacker]) { const sq = square - attackDirection; if ((sq & 0x88) === 0 && position.board[sq] === nonSlidingAttacker) { result.push(sq); } } } function findSlidingAttacks(position: PositionImpl, square: number, result: number[], slidingAttacker: number, queenAttacker: number) { for (const attackDirection of ATTACK_DIRECTIONS[slidingAttacker]) { let sq = square; while (true) { sq -= attackDirection; if ((sq & 0x88) === 0) { const cp = position.board[sq]; if (cp === SpI.EMPTY) { continue; } else if (cp === slidingAttacker || cp === queenAttacker) { result.push(sq); } } break; } } }