UNPKG

xchess

Version:

Chess Engine

420 lines (331 loc) 6.13 kB
export {Square, squares, at} import {files} from './file.js' import {ranks} from './rank.js' import {white, black} from './color.js' import {INVALID_SQUARE} from './errors.js' import {ConstNumberObject} from './ansi-style.js' import {inspect} from './inspect.js' const squares = []; const ReverseSquares = []; const map = new Map(); function codeAt({x, y}){ return x + y * files.length; } function iccfAt({file, rank}){ return String(file.iccf + rank.iccf); } function nameAt({file, rank}){ return `${file}${rank}`; } function colorAt({x, y}){ return ((x + y) & 1) ? black : white; } function A({x, y}){ return x + y; } function B({x, y}){ return x - y; } function at(x, y){ return files[x]?.squares[y] ?? null; } function from(value){ const square = map.get(value); if(square) return square; throw INVALID_SQUARE(value); } function is(value){ return map.has(value); } function list(... squares){ const list = []; for(const square of squares) if(square) list.push(square); return Object.freeze(list); } function near(target){ return list( target.topLeft, target.top, target.topRight, target.left, target.right, target.bottomLeft, target.bottom, target.bottomRight, ); } function L(target){ return list( target.to(2, 1), target.to(1, 2), target.to(-1, 2), target.to(-2, 1), target.to(-2, -1), target.to(-1, -2), target.to(1, -2), target.to(2, -1), ); } function topD(target){ return list(target.topLeft, target.topRight); } function bottomD(target){ return list(target.bottomLeft, target.bottomRight); } class Square { static from(value){ return from(value); } static is(value){ return is(value); } static at(x, y){ return at(x, y); } static all(){ return squares; } static reverse(){ return ReverseSquares; } static InitSquares(){ // check once if(squares.length > 0) throw Error('do not use this method!'); // generate squares for(const rank of ranks){ for(const file of files){ const square = new Square(file, rank); rank.squares.push(square); file.squares.push(square); map.set(square, square); map.set(square.code, square); map.set(square.iccf, square); map.set(square.name, square); map.set(square.name.toUpperCase(), square); squares.push(square); ReverseSquares.unshift(square); } } // bind squares for(const square of squares){ square.#topLeft = square.to(-1, -1), square.#top = square.to(0, -1), square.#topRight = square.to(1, -1), square.#left = square.to(-1, 0), square.#right = square.to(1, 0), square.#bottomLeft = square.to(-1, 1), square.#bottom = square.to(0, 1), square.#bottomRight = square.to(1, 1), square.#near = near(square); square.#L = L(square); square.#topD = topD(square); square.#bottomD = bottomD(square); } // freeze collections for(const rank of ranks) Object.freeze(rank.squares); for(const file of files) Object.freeze(file.squares); Object.freeze(squares); } // Stat #file; #rank; #code; #iccf; #name; #color; // Geo #a; #b; #top; #left; #right; #bottom; #topLeft; #topRight; #bottomLeft; #bottomRight; #L; #near; #topD; #bottomD; constructor(file, rank){ this.#file = file; this.#rank = rank; this.#code = codeAt(this); this.#iccf = iccfAt(this); this.#name = nameAt(this); this.#color = colorAt(this); this.#a = A(this); this.#b = B(this); } get file(){ return this.#file; } get rank(){ return this.#rank; } get code(){ return this.#code; } get iccf(){ return this.#iccf; } get name(){ return this.#name; } get color(){ return this.#color; } valueOf(){ return this.code; } toString(){ return this.name; } toJSON(){ return this.name; } [inspect.custom](depth, opts){ return ConstNumberObject(`[Square ${this.name.toUpperCase()}]`); } // Geo get x(){ return this.file.x; } get y(){ return this.rank.y; } get a(){ return this.#a; } get b(){ return this.#b; } eq(square){ return this === from(square); } dx(square){ return from(square).x - this.x; } dy(square){ return from(square).y - this.y; } compare(square){ return [this.dx(square), this.dy(square)]; } isNear(square){ return this.#near.includes(from(square)); } isL(square){ return this.#L.includes(from(square)); } isTopD(square){ return this.#topD.includes(from(square)); } isBottomD(square){ return this.#bottomD.includes(from(square)); } // square to(dx, dy){ return at(this.x + dx, this.y + dy); } get topLeft(){ return this.#topLeft; } get top(){ return this.#top; } get topRight(){ return this.#topRight; } get left(){ return this.#left; } get right(){ return this.#right; } get bottomLeft(){ return this.#bottomLeft; } get bottom(){ return this.#bottom; } get bottomRight(){ return this.#bottomRight; } // squares get near(){ return this.#near; } get L(){ return this.#L; } get topD(){ return this.#topD; } get bottomD(){ return this.#bottomD; } * walkTopLeft(){ let next = this; while(next = next.topLeft) yield next; } * walkTop(){ let next = this; while(next = next.top) yield next; } * walkTopRight(){ let next = this; while(next = next.topRight) yield next; } * walkLeft(){ let next = this; while(next = next.left) yield next; } * walkRight(){ let next = this; while(next = next.right) yield next; } * walkBottomLeft(){ let next = this; while(next = next.bottomLeft) yield next; } * walkBottom(){ let next = this; while(next = next.bottom) yield next; } * walkBottomRight(){ let next = this; while(next = next.bottomRight) yield next; } * walkT(){ yield this.walkTop(); yield this.walkRight(); yield this.walkBottom(); yield this.walkLeft(); } * walkX(){ yield this.walkTopRight(); yield this.walkBottomRight(); yield this.walkBottomLeft(); yield this.walkTopLeft(); } * walkAll(){ yield * this.walkT(); yield * this.walkX(); } } Square.InitSquares();