UNPKG

chessground12

Version:
128 lines (111 loc) 3.59 kB
import { Color, Geometry, Key, Pieces, Variant } from './types'; import { allPos, key2pos, pos2key } from './util'; type Mobility = (x1: number, y1: number, x2: number, y2: number) => boolean; function diff(a: number, b: number): number { return Math.abs(a - b); } function pawn(color: Color): Mobility { return (x1, y1, x2, y2) => diff(x1, x2) < 2 && (color === 'white' ? // allow 2 squares from first two ranks, for horde y2 === y1 + 1 || (y1 <= 1 && y2 === y1 + 2 && x1 === x2) : y2 === y1 - 1 || (y1 >= 6 && y2 === y1 - 2 && x1 === x2)); } export const knight: Mobility = (x1, y1, x2, y2) => { const xd = diff(x1, x2); const yd = diff(y1, y2); return (xd === 1 && yd === 2) || (xd === 2 && yd === 1); }; export const giraffe: Mobility = (x1, y1, x2, y2) => { const xd = diff(x1, x2); const yd = diff(y1, y2); return (xd === 1 && yd === 4) || (xd === 4 && yd === 1); }; const bishop: Mobility = (x1, y1, x2, y2) => { return diff(x1, x2) === diff(y1, y2); }; const rook: Mobility = (x1, y1, x2, y2) => { return x1 === x2 || y1 === y2; }; export const queen: Mobility = (x1, y1, x2, y2) => { return bishop(x1, y1, x2, y2) || rook(x1, y1, x2, y2); }; function king(color: Color, rookFiles: number[], canCastle: boolean): Mobility { return (x1, y1, x2, y2) => (diff(x1, x2) < 2 && diff(y1, y2) < 2) || (canCastle && y1 === y2 && y1 === (color === 'white' ? 0 : 7) && ((x1 === 4 && ((x2 === 2 && rookFiles.includes(0)) || (x2 === 6 && rookFiles.includes(7)))) || rookFiles.includes(x2))); } function rookFilesOf(pieces: Pieces, color: Color) { const backrank = color === 'white' ? '1' : '8'; const files = []; for (const [key, piece] of pieces) { if (key[1] === backrank && piece.color === color && piece.role === 'r-piece') { files.push(key2pos(key)[0]); } } return files; } // capablanca king (different castling files from standard chess king) // archbishop (knight + bishop) const archbishop: Mobility = (x1, y1, x2, y2) => { return bishop(x1, y1, x2, y2) || knight(x1, y1, x2, y2); }; // chancellor (knight + rook) const chancellor: Mobility = (x1, y1, x2, y2) => { return rook(x1, y1, x2, y2) || knight(x1, y1, x2, y2); }; export function premove( pieces: Pieces, key: Key, canCastle: boolean, geom: Geometry, variant: Variant, ): Key[] { const piece = pieces.get(key)!; const role = piece.role; const color = piece.color; const pos = key2pos(key); let mobility: Mobility = () => false; switch (variant) { default: switch (role) { case 'p-piece': mobility = pawn(color); break; // pawn case 'r-piece': mobility = rook; break; // rook case 'n-piece': mobility = knight; break; // knight case 'b-piece': mobility = bishop; break; // bishop case 'q-piece': mobility = queen; break; // queen case 'c-piece': mobility = chancellor; break; // chancellor case 'h-piece': // S-chess hawk case 'a-piece': mobility = archbishop; break; // archbishop case 'g-piece': mobility = giraffe; break; case 'k-piece': mobility = king(color, rookFilesOf(pieces, color), canCastle); break; // king } } let keys = allPos(geom) .filter(pos2 => (pos[0] !== pos2[0] || pos[1] !== pos2[1]) && mobility(pos[0], pos[1], pos2[0], pos2[1])) .map(pos2key); return keys; }