UNPKG

svelte4-chess

Version:

Fully playable chess component for Svelte 4. Powered by Chess.js logic, Chessground chessboard and optionally Stockfish chess AI.

101 lines (100 loc) 3.51 kB
; var State; (function (State) { State["Uninitialised"] = "uninitialised"; State["Initialising"] = "initialising"; State["Waiting"] = "waiting"; State["Searching"] = "searching"; })(State || (State = {})); ; export class Engine { stockfish; state = State.Uninitialised; moveTime; depth; color; stockfishPath; externalUciCallback = undefined; // Callbacks used when waiting for specific UCI messages onUciOk = undefined; // "uciok" marks end of initialisation onBestMove = undefined; // "uciok", used during initialisation // Constructor constructor(options = {}) { this.moveTime = options.moveTime || 2000; this.depth = options.depth || 40; this.color = options.color || 'b'; this.stockfishPath = options.stockfishPath || 'stockfish.js'; } // Initialise Stockfish. Resolve promise after receiving uciok. init() { return new Promise((resolve) => { this.state = State.Initialising; // NOTE: stockfish.js is not part of the npm package due to its size (1-2 MB). // You can find the file here: https://github.com/gtim/svelte-chess/tree/main/static this.stockfish = new Worker(this.stockfishPath); this.stockfish.addEventListener('message', (e) => this._onUci(e)); this.onUciOk = () => { if (this.state === State.Initialising) { this.state = State.Waiting; this.onUciOk = undefined; resolve(); } }; this.stockfish.postMessage('uci'); }); } // Callback when receiving UCI messages from Stockfish. _onUci({ data }) { const uci = data; if (this.onUciOk && uci === 'uciok') { this.onUciOk(); } if (this.onBestMove && uci.slice(0, 8) === 'bestmove') { this.onBestMove(uci); } if (this.externalUciCallback) { this.externalUciCallback(uci); } } setUciCallback(callback) { this.externalUciCallback = callback; } getMove(fen) { return new Promise((resolve) => { if (!this.stockfish) throw new Error('Engine not initialised'); if (this.state !== State.Waiting) throw new Error('Engine not ready (state: ' + this.state + ')'); this.state = State.Searching; this.stockfish.postMessage('position fen ' + fen); this.stockfish.postMessage(`go depth ${this.depth} movetime ${this.moveTime}`); this.onBestMove = (uci) => { const uciArray = uci.split(' '); const bestMoveLan = uciArray[1]; this.state = State.Waiting; this.onBestMove = undefined; resolve(bestMoveLan); }; }); } getColor() { return this.color; } isSearching() { return this.state === State.Searching; } async stopSearch() { return new Promise((resolve) => { if (!this.stockfish) throw new Error('Engine not initialised'); if (this.state !== State.Searching) resolve(); this.onBestMove = (uci) => { this.state = State.Waiting; this.onBestMove = undefined; resolve(); }; this.stockfish.postMessage('stop'); }); } }