xchess
Version:
Chess Engine
350 lines (264 loc) • 4.8 kB
JavaScript
export {Piece, King, Queen, Rook, Bishop, Knight, Pawn}
import {Color, white, black} from './color.js'
import * as pawn from './pawn.js'
import {IS_STRING} from './types.js'
import {
INVALID_PIECE,
INVALID_PIECE_COLOR,
} from './errors.js'
const Types = new Map();
const ColorTypes = new Map();
function InitTypes(... types){
for(const type of types)
AddType(type);
}
function AddType(Type){
Types.set(Type.char.toLowerCase(), Type);
Types.set(Type.name.toLowerCase(), Type);
AddTypeColor(Type, white);
AddTypeColor(Type, black);
}
function AddTypeColor(Type, Color){
const Creator = PieceCreator(Type, Color);
ColorTypes.set(Color.codeOf(Type.code), Creator);
ColorTypes.set(Type.signs[+ Color], Creator);
ColorTypes.set(Color.fenOf(Type.char), Creator);
}
function PieceCreator(Type, Color){
return () => new Type(Color);
}
function from(value){
if(Piece.is(value))
return value;
const Create = ColorTypes.get(value);
if(Create)
return Create();
throw INVALID_PIECE(value);
}
function fromColor(value, color){
if(Piece.is(value)){
if(value.color.eq(color))
return value;
throw INVALID_PIECE_COLOR(value.color);
}
if(IS_STRING(value)){
const Type = Types.get(value.toLowerCase());
if(Type) return new Type(color);
} throw INVALID_PIECE(value);
}
class Piece {
static is(value){
return value instanceof this;
}
static validate(value){
if(this.is(value))
return value;
throw INVALID_PIECE(value);
}
static from(value){
return from(value);
}
static fromColor(value, color){
return fromColor(value, color);
}
static get code(){
return NaN;
}
static get char(){
return '�';
}
static get signs(){
return '��';
}
static get weight(){
return 0;
}
#color;
constructor(color){
this.#color = Color.from(color);
}
get color(){
return this.#color;
}
get code(){
return this.color.codeOf(this.constructor.code);
}
get name(){
return this.constructor.name;
}
get sign(){
return this.constructor.signs[+ this.color];
}
get char(){
return this.constructor.char;
}
get fen(){
return this.color.fenOf(this.char);
}
get moveLetter(){
return this.char;
}
get weight(){
return this.constructor.weight;
}
valueOf(){
return this.code;
}
toString(){
return this.sign;
}
toJSON(){
return this.fen;
}
clone(){
return new this.constructor(this.color);
}
// rules
opposite(piece){
const target = Piece.from(piece);
return this.color.opposite(target.color);
}
moves(context){
const moves = [];
const {board} = context;
for(const move of this.allMoves(context))
if(!move.check(board)) moves.push(move);
return moves;
}
allMoves(context){
return [];
}
test(target, board){
return false;
}
}
class King extends Piece {
static get code(){
return 0;
}
static get char(){
return 'K';
}
static get signs(){
return '♔♚';
}
// rules
allMoves(context){
return [
... context.board.near(this),
... context.castling.moves(context),
];
}
test(target, board){
return board.isNear(this, target);
}
}
class Queen extends Piece {
static get code(){
return 1;
}
static get char(){
return 'Q';
}
static get signs(){
return '♕♛';
}
static get weight(){
return 9;
}
// rules
allMoves(context){
return context.board.traceAll(this);
}
test(target, board){
return board.crossAny(this, target);
}
}
class Rook extends Piece {
static get code(){
return 2;
}
static get char(){
return 'R';
}
static get signs(){
return '♖♜';
}
static get weight(){
return 5;
}
// rules
allMoves(context){
return context.board.traceT(this);
}
test(target, board){
return board.crossT(this, target);
}
}
class Bishop extends Piece {
static get code(){
return 3;
}
static get char(){
return 'B';
}
static get signs(){
return '♗♝';
}
static get weight(){
return 3;
}
// rules
allMoves(context){
return context.board.traceX(this);
}
test(target, board){
return board.crossX(this, target);
}
}
class Knight extends Piece {
static get code(){
return 4;
}
static get char(){
return 'N';
}
static get signs(){
return '♘♞';
}
static get weight(){
return 3;
}
// rules
allMoves(context){
return context.board.L(this);
}
test(target, board){
return board.isL(this, target);
}
}
class Pawn extends Piece {
static get code(){
return 5;
}
static get char(){
return 'P';
}
static get signs(){
return '♙♟';
}
get moveLetter(){
return '';
}
static get weight(){
return 1;
}
// rules
allMoves(context){
return [... pawn.allMoves(this, context)];
}
test(target, board){
return pawn.test(this, target, board);
}
}
InitTypes(King, Queen, Rook, Bishop, Knight, Pawn);