feat : init Stockfish
This commit is contained in:
121
src/lib/engine/stockfish/index.ts
Normal file
121
src/lib/engine/stockfish/index.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
export class Stockfish {
|
||||
private worker: Worker;
|
||||
|
||||
constructor() {
|
||||
this.worker = new Worker(
|
||||
this.isWasmSupported() ? "./stockfish.wasm.js" : "./stockfish.js"
|
||||
);
|
||||
|
||||
this.sendCommands(["uci"], "uciok");
|
||||
this.sendCommands(["setoption name MultiPV value 2", "isready"], "readyok");
|
||||
|
||||
console.log("Stockfish created");
|
||||
}
|
||||
|
||||
public isWasmSupported(): boolean {
|
||||
return (
|
||||
typeof WebAssembly === "object" &&
|
||||
WebAssembly.validate(
|
||||
Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private async sendCommands(
|
||||
commands: string[],
|
||||
finalMessage: string
|
||||
): Promise<string[]> {
|
||||
return new Promise((resolve) => {
|
||||
const messages: string[] = [];
|
||||
this.worker.onmessage = (event) => {
|
||||
const messageData: string = event.data;
|
||||
messages.push(messageData);
|
||||
if (messageData.startsWith(finalMessage)) {
|
||||
resolve(messages);
|
||||
}
|
||||
};
|
||||
|
||||
for (const command of commands) {
|
||||
this.worker.postMessage(command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async evaluateGame(fens: string[], depth = 16): Promise<GameEval> {
|
||||
await this.sendCommands(["ucinewgame", "isready"], "readyok");
|
||||
this.worker.postMessage("position startpos");
|
||||
|
||||
const moves: MoveEval[] = [];
|
||||
for (const fen of fens) {
|
||||
const result = await this.evaluatePosition(fen, depth);
|
||||
moves.push(result);
|
||||
}
|
||||
|
||||
return { moves };
|
||||
}
|
||||
|
||||
public async evaluatePosition(fen: string, depth = 16): Promise<MoveEval> {
|
||||
const results = await this.sendCommands(
|
||||
[`position fen ${fen}`, `go depth ${depth}`],
|
||||
"bestmove"
|
||||
);
|
||||
return this.parseResults(results);
|
||||
}
|
||||
|
||||
private parseResults(results: string[]): MoveEval {
|
||||
const parsedResults: MoveEval = {
|
||||
bestMove: "",
|
||||
lines: [],
|
||||
};
|
||||
|
||||
for (const result of results) {
|
||||
if (result.startsWith("bestmove")) {
|
||||
const bestMove = this.getResultProperty(result, "bestmove");
|
||||
if (bestMove) {
|
||||
parsedResults.bestMove = bestMove;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.startsWith("info")) {
|
||||
const pv = this.getResultPv(result);
|
||||
const score = this.getResultProperty(result, "cp");
|
||||
const mate = this.getResultProperty(result, "mate");
|
||||
|
||||
if (pv) {
|
||||
parsedResults.lines.push({
|
||||
pv,
|
||||
score: score ? parseInt(score) : undefined,
|
||||
mate: mate ? parseInt(mate) : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parsedResults;
|
||||
}
|
||||
|
||||
private getResultProperty(
|
||||
result: string,
|
||||
property: string
|
||||
): string | undefined {
|
||||
const splitResult = result.split(" ");
|
||||
const propertyIndex = splitResult.indexOf(property);
|
||||
|
||||
if (propertyIndex === -1 || propertyIndex + 1 >= splitResult.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return splitResult[propertyIndex + 1];
|
||||
}
|
||||
|
||||
private getResultPv(result: string): string[] | undefined {
|
||||
const splitResult = result.split(" ");
|
||||
const pvIndex = splitResult.indexOf("pv");
|
||||
|
||||
if (pvIndex === -1 || pvIndex + 1 >= splitResult.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return splitResult.slice(pvIndex + 1);
|
||||
}
|
||||
}
|
||||
37
src/lib/engine/stockfish/stockfish.js
Normal file
37
src/lib/engine/stockfish/stockfish.js
Normal file
File diff suppressed because one or more lines are too long
BIN
src/lib/engine/stockfish/stockfish.wasm
Normal file
BIN
src/lib/engine/stockfish/stockfish.wasm
Normal file
Binary file not shown.
19
src/lib/engine/stockfish/stockfish.wasm.js
Normal file
19
src/lib/engine/stockfish/stockfish.wasm.js
Normal file
File diff suppressed because one or more lines are too long
14
src/types/eval.ts
Normal file
14
src/types/eval.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
interface MoveEval {
|
||||
bestMove: string;
|
||||
lines: LineEval[];
|
||||
}
|
||||
|
||||
interface LineEval {
|
||||
pv: string[];
|
||||
score?: number;
|
||||
mate?: number;
|
||||
}
|
||||
|
||||
interface GameEval {
|
||||
moves: MoveEval[];
|
||||
}
|
||||
Reference in New Issue
Block a user