import { Chess } from "chess.js"; export class Game { constructor(fen) { this.chess = new Chess(fen); } get fen() { return this.chess.fen(); } get turn() { return this.chess.turn(); } board() { return this.chess.board(); } legalFrom(square) { return this.chess.moves({ square, verbose: true }); } legalTargets(square) { return this.legalFrom(square); } allMoves() { return this.chess.moves({ verbose: true }); } legalUci() { return this.allMoves().map((m) => m.from + m.to + (m.promotion ?? "")); } // Accepts a UCI-style from/to (plus promotion) and returns the applied move, or null. play(from, to, promotion) { try { return this.chess.move({ from, to, promotion: promotion ?? "q" }); } catch { return null; } } playUci(uci) { const from = uci.slice(0, 2); const to = uci.slice(2, 4); const promo = uci.length > 4 ? uci[4] : undefined; return this.play(from, to, promo); } undo() { return this.chess.undo(); } history() { return this.chess.history({ verbose: true }); } inCheck() { return this.chess.inCheck(); } get(square) { return this.chess.get(square); } attackers(square, color) { return this.chess.attackers(square, color); } clone() { return new Game(this.fen); } pieces(color) { const out = []; for (const row of this.chess.board()) { for (const cell of row) { if (cell && cell.color === color) out.push({ square: cell.square, type: cell.type }); } } return out; } // The square of the side-to-move's king, used to paint the check marker. kingSquare(color) { for (const row of this.chess.board()) { for (const cell of row) { if (cell && cell.type === "k" && cell.color === color) return cell.square; } } return null; } outcome() { if (!this.chess.isGameOver()) return { over: false }; if (this.chess.isCheckmate()) { return { over: true, reason: "checkmate", winner: this.turn === "w" ? "b" : "w" }; } if (this.chess.isStalemate()) return { over: true, reason: "stalemate" }; if (this.chess.isInsufficientMaterial()) return { over: true, reason: "insufficient" }; if (this.chess.isThreefoldRepetition()) return { over: true, reason: "repetition" }; if (this.chess.isDrawByFiftyMoves?.()) return { over: true, reason: "fifty" }; return { over: true, reason: "draw" }; } pgn() { return this.chess.pgn(); } loadPgn(pgn) { try { this.chess.loadPgn(pgn); return true; } catch { return false; } } load(fen) { try { this.chess.load(fen); return true; } catch { return false; } } }