Skip to content

Commit

Permalink
Make the Search configurable from outside
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielCTroia committed Nov 25, 2021
1 parent b32a0e4 commit acbd59b
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 26 deletions.
68 changes: 53 additions & 15 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import bodyParser from "body-parser";
import { GameRecord } from "dstnd-io";
import express, { Application, Request, Response } from "express";
import { Engine } from "node-uci";
import { Analyzer, GameToAnalyze } from "./src/Engine";
import { SearchOptions } from "node-uci";
import { Analyzer, AnalyzerOpts, GameToAnalyze } from "./src/Engine";

const app: Application = express();
const port = 5454;
Expand All @@ -15,15 +15,25 @@ app.use(bodyParser.json());

const analyzersByGameId: Record<GameRecord["id"], Analyzer> = {};

const getExistentAnalyzerOrCreateNew = (game: GameToAnalyze) => {
const getExistentAnalyzerByGameId = (gameId: GameToAnalyze["id"]) => {
const { [gameId]: engine } = analyzersByGameId;

return engine;
};

const getExistentAnalyzerOrCreateNew = (
game: GameToAnalyze,
opts?: AnalyzerOpts
) => {
const { [game.id]: engine } = analyzersByGameId;

if (engine && !engine.hasQuit) {
return engine;
}

analyzersByGameId[game.id] = new Analyzer(game, {
searchOpts: { depth: 10, nodes: 25000 },
...{ searchOpts: { depth: 25, nodes: 25 * 10000 } },
...opts,
});

return analyzersByGameId[game.id];
Expand All @@ -35,6 +45,8 @@ app.get("/", async (req, res) => {

const engineRes = await engine.updateAndSearchOnce(fen);

await engine.quit();

return res.status(200).send({
ok: true,
engineRes,
Expand All @@ -43,26 +55,52 @@ app.get("/", async (req, res) => {

app.post("/analyze", async (req: Request, res: Response) => {
try {
const { gameId, fen } = req.body;
const { gameId, fen, searchOpts } = req.body;

if (!(gameId && fen)) {
throw new Error("Body not good");
}

const engine = getExistentAnalyzerOrCreateNew({ id: gameId, fen });

const engine = getExistentAnalyzerOrCreateNew(
{ id: gameId, fen },
typeof searchOpts === "object"
? { searchOpts: searchOpts as SearchOptions }
: {}
);
const engineRes = await engine.updateAndSearchOnce(fen);

// console.log("engine res", engineRes);

return res.status(200).send({
// message: "ok",
// works: 'good',
// ...req.body,
...engineRes,
return res.status(200).send(engineRes);
} catch (e) {
console.error("Engine errror", e);
return res.status(500).send({
error: e,
});
}
});

app.post("/quit", async (req: Request, res: Response) => {
try {
const { gameId } = req.body;

if (!gameId) {
throw new Error("Body not good");
}

const engine = getExistentAnalyzerByGameId(gameId);

if (!engine) {
return res.status(200).send({ message: "Engine Not Existent" });
}

if (engine.hasQuit) {
return res.status(200).send({ message: "Engine Already Quitted" });
}

await engine.quit();

return res.status(200).send({ message: "Engine Quitted" });
} catch (e) {
console.error("Stockfish errror", e);
console.error("Engine errror", e);
return res.status(500).send({
error: e,
});
Expand Down
26 changes: 15 additions & 11 deletions src/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export type GameToAnalyze = {
fen: ChessGameStateFen;
};

type Opts = {
searchOpts: SearchOptions;
searchInfiniteOpts: SearchOptions;
searchInfiniteWaitMs: number;
export type AnalyzerOpts = {
searchOpts?: SearchOptions;
searchInfiniteOpts?: SearchOptions;
searchInfiniteWaitMs?: number;
};

// const transformSearchResult = (data: SearchResult) => {
Expand All @@ -29,34 +29,38 @@ export class Analyzer {

private initiatedEngine: Promise<Engine>;

private opts: Opts = {
private opts: AnalyzerOpts = {
searchOpts: { depth: 7, nodes: 2500 },
searchInfiniteOpts: { depth: 3, nodes: 250 },
searchInfiniteWaitMs: 5 * 1000,
};

constructor(private game: GameToAnalyze, opts: Partial<Opts> = {}) {
constructor(private game: GameToAnalyze, opts: Partial<AnalyzerOpts> = {}) {
this.opts = {
...this.opts,
...opts,
};

this.initiatedEngine = this.initiate(
new Engine("/stockfish/stockfish"),
// new Engine("/opt/homebrew/bin/stockfish"),
game
);
}

private async initiate(engine: Engine, game: GameToAnalyze) {
await engine.init();
await engine.setoption("UCI_AnalyseMode", "true");
await engine.setoption("MultiPV", "4");
await engine.setoption("MultiPV", "3");
await engine.setoption("Hash", "50");
await engine.isready();
await engine.ucinewgame();
await engine.position(game.fen);

console.log("[Analyzer] Engine Initiated", {
gameId: this.game.id,
opts: (engine as any).options,
gameId: game.id,
engineOpts: (engine as any).options,
config: this.opts,
});

return engine;
Expand All @@ -79,7 +83,7 @@ export class Analyzer {

await engine.isready();

return await engine.go(this.opts.searchOpts);
return await engine.go(this.opts.searchOpts || {});
}

async updateAndSearchInfinite(fen: ChessGameStateFen, onFound: () => {}) {
Expand All @@ -88,7 +92,7 @@ export class Analyzer {

await engine.isready();

const emitter = engine.goInfinite(this.opts.searchInfiniteOpts);
const emitter = engine.goInfinite(this.opts.searchInfiniteOpts || {});

emitter.on("data", (a) => {
// TODO: Test
Expand Down

0 comments on commit acbd59b

Please sign in to comment.