UNPKG

xchess

Version:

Chess Engine

311 lines (245 loc) 5.42 kB
export {Castling} import {white, black} from './color.js' import {ranks} from './rank.js' import {King, Rook} from './piece.js' import {Move, KingsideCastling, QueensideCastling} from './move.js' import {INVALID_COLOR} from './errors.js' class Castling { static from(context){ return CreateFrom(context.color, context); } static prevFrom(context){ return CreatePrevFrom(context.color, context); } // Config get kingside(){ return false; } get queenside(){ return false; } // Rules next(move){ return this; } * moves(context){ // abstract } } class IdleCastling extends Castling {} class SingleCastling extends Castling {} const Idle = new IdleCastling(); const WhiteCreator = CastlingCreator(white, ranks[7]); const BlackCreator = CastlingCreator(black, ranks[0]); function CreateFrom(color, context){ if(white.eq(color)) return new CreateWhite(context); if(black.eq(color)) return new CreateBlack(context); throw INVALID_COLOR(color); } function CreatePrevFrom(color, context){ return CreateFrom(color.invert(), context); } function CreateWhite({board, wk, wq}){ return WhiteCreator(board, wk, wq); } function CreateBlack({board, bk, bq}){ return BlackCreator(board, bk, bq); } function CastlingCreator(color, rank){ const [A, B, C, D, E, F, G, H] = rank.squares; function IsKing(piece){ return King.is(piece) && color.eq(piece.color); } function IsRook(piece){ return Rook.is(piece) && color.eq(piece.color); } function GetKing(board){ const king = board.get(E); if(IsKing(king)) return king; } function GetKRook(board){ const rook = board.get(H); if(IsRook(rook)) return rook; } function GetQRook(board){ const rook = board.get(A); if(IsRook(rook)) return rook; } function TestAt(board, square){ if(board.has(square)) return false; if(board.testAt(square, color)) return false; return true; } function TestKingside(board){ if(!TestAt(board, F)) return false; if(!TestAt(board, G)) return false; return true; } function TestQueenside(board){ if(board.has(B)) return false; if(!TestAt(board, C)) return false; if(!TestAt(board, D)) return false; return true; } function KingMove(king, rook){ const submove = new Move(rook, H, F); return new KingsideCastling(king, E, G, submove); } function QueenMove(king, rook){ const submove = new Move(rook, A, D); return new QueensideCastling(king, E, C, submove); } function * KingMoves({isCheck, board}, king, rook){ if(!isCheck && TestKingside(board)) yield KingMove(king, rook); } function * QueenMoves({isCheck, board}, king, rook){ if(!isCheck && TestQueenside(board)) yield QueenMove(king, rook); } class TwinCastling extends Castling { #king; #krook; #qrook; constructor(king, krook, qrook){ super(); this.#king = king; this.#krook = krook; this.#qrook = qrook; } get king(){ return this.#king; } get krook(){ return this.#krook; } get qrook(){ return this.#qrook; } get kingside(){ return true; } get queenside(){ return true; } // Rules next(move){ if(move.includes(this.king)) return Idle; if(move.includes(this.krook)) return new QueenCastling(this.king, this.qrook); if(move.includes(this.qrook)) return new KingCastling(this.king, this.krook); return this; } * moves(context){ yield * KingMoves(context, this.king, this.krook); yield * QueenMoves(context, this.king, this.qrook); } } class KingCastling extends Castling { #king; #rook; constructor(king, rook){ super(); this.#king = king; this.#rook = rook; } get king(){ return this.#king; } get rook(){ return this.#rook; } get kingside(){ return true; } // Rules next(move){ if(move.includes(this.king)) return Idle; if(move.includes(this.rook)) return Idle; return this; } moves(context){ return KingMoves(context, this.king, this.rook); } } class QueenCastling extends Castling { #king; #rook; constructor(king, rook){ super(); this.#king = king; this.#rook = rook; } get king(){ return this.#king; } get rook(){ return this.#rook; } get queenside(){ return true; } // Rules next(move){ if(move.includes(this.king)) return Idle; if(move.includes(this.rook)) return Idle; return this; } moves(context){ return QueenMoves(context, this.king, this.rook); } } function CreateTwin(board){ const king = GetKing(board); if(king){ const krook = GetKRook(board); const qrook = GetQRook(board); if(krook){ if(qrook) return new TwinCastling(king, krook, qrook); return new KingCastling(king, krook); } if(qrook) return new QueenCastling(king, qrook); } return Idle; } function CreateKing(board){ const king = GetKing(board); const rook = GetKRook(board); if(king && rook) return new KingCastling(king, rook); return Idle; } function CreateQueen(board){ const king = GetKing(board); const rook = GetQRook(board); if(king && rook) return new QueenCastling(king, rook); return Idle; } function CreateCastling(board, kingside, queenside){ if(kingside){ if(queenside) return CreateTwin(board); return CreateKing(board); } if(queenside) return CreateQueen(board); return Idle; } return CreateCastling; }