Skip to content

Commit

Permalink
Fix USI monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
sunfish-shogi committed Feb 6, 2025
1 parent e36e559 commit fb48813
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 142 deletions.
17 changes: 8 additions & 9 deletions src/renderer/players/usi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ import { Player, SearchInfo, SearchHandler, MateHandler } from "./player";
import { GameResult } from "@/common/game/result";
import { TimeStates } from "@/common/game/time";

type onReceiveUSIBestMoveHandler = (
sessionID: number,
position: ImmutablePosition,
usiMove: string,
) => void;
type onStartSearchHandler = (sessionID: number, position: ImmutablePosition) => void;

type onUpdateUSIInfoHandler = (
sessionID: number,
Expand All @@ -27,11 +23,11 @@ type onUpdateUSIInfoHandler = (
ponderMove?: Move,
) => void;

let onReceiveUSIBestMove: onReceiveUSIBestMoveHandler = () => {};
let onStartSearch: onStartSearchHandler = () => {};
let onUpdateUSIInfo: onUpdateUSIInfoHandler = () => {};

export function setOnReceiveUSIBestMoveHandler(handler: onReceiveUSIBestMoveHandler) {
onReceiveUSIBestMove = handler;
export function setOnStartSearchHandler(handler: onStartSearchHandler) {
onStartSearch = handler;
}

export function setOnUpdateUSIInfoHandler(handler: onUpdateUSIInfoHandler) {
Expand Down Expand Up @@ -92,6 +88,7 @@ export class USIPlayer implements Player {
} else {
this.info = undefined;
await api.usiGo(this.sessionID, this.usi, timeStates);
onStartSearch(this.sessionID, this.position);
}
this.ponderMove = undefined;
this.ponder = undefined;
Expand Down Expand Up @@ -132,6 +129,7 @@ export class USIPlayer implements Player {
this.info = undefined;
this.ponderMove = ponderMove;
await api.usiGoPonder(this.sessionID, this.ponder, timeStates);
onStartSearch(this.sessionID, this.position);
}

async startMateSearch(
Expand All @@ -145,6 +143,7 @@ export class USIPlayer implements Player {
this.position = position.clone();
this.mateHandler = handler;
await api.usiGoMate(this.sessionID, this.usi);
onStartSearch(this.sessionID, this.position);
}

async startResearch(position: ImmutablePosition, usi: string): Promise<void> {
Expand All @@ -153,6 +152,7 @@ export class USIPlayer implements Player {
this.info = undefined;
this.position = position.clone();
await api.usiGoInfinite(this.sessionID, usi);
onStartSearch(this.sessionID, this.position);
}

async stop(): Promise<void> {
Expand Down Expand Up @@ -183,7 +183,6 @@ export class USIPlayer implements Player {
if (usi !== this.usi) {
return;
}
onReceiveUSIBestMove(this.sessionID, this.position, usiMove);
if (usiMove === "resign") {
searchHandler.onResign();
return;
Expand Down
32 changes: 16 additions & 16 deletions src/renderer/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import { t } from "@/common/i18n";
import { MateSearchManager } from "./mate";
import { detectUnsupportedRecordProperties } from "@/renderer/helpers/record";
import { RecordFileFormat, detectRecordFileFormatByPath } from "@/common/file/record";
import { setOnReceiveUSIBestMoveHandler, setOnUpdateUSIInfoHandler } from "@/renderer/players/usi";
import { setOnStartSearchHandler, setOnUpdateUSIInfoHandler } from "@/renderer/players/usi";
import { useErrorStore } from "./error";
import { useBusyState } from "./busy";
import { Confirmation, useConfirmationStore } from "./confirm";
Expand Down Expand Up @@ -206,7 +206,7 @@ class Store {
.on("notImplemented", this.onNotImplemented.bind(refs))
.on("noMate", this.onNoMate.bind(refs))
.on("error", this.onCheckmateError.bind(refs));
setOnReceiveUSIBestMoveHandler(this.endUSIInfoIteration.bind(refs));
setOnStartSearchHandler(this.endUSIIteration.bind(refs));
setOnUpdateUSIInfoHandler(this.updateUSIInfo.bind(refs));
}

Expand Down Expand Up @@ -462,23 +462,23 @@ class Store {
}
let entryCount = 0;
let maxScore = -Infinity;
for (const iteration of session.latestIteration) {
for (const info of session.latestInfo) {
if (entryCount >= appSettings.maxArrowsPerEngine) {
break;
}
if (iteration.multiPV && iteration.multiPV > appSettings.maxArrowsPerEngine) {
if (info.multiPV && info.multiPV > appSettings.maxArrowsPerEngine) {
break;
}
if (!iteration.pv?.length) {
if (!info.pv?.length) {
continue;
}
const score =
iteration.score !== undefined
? iteration.score
: iteration.scoreMate
? iteration.scoreMate > 0
? 1e8 - iteration.scoreMate
: -1e8 - iteration.scoreMate
info.score !== undefined
? info.score
: info.scoreMate
? info.scoreMate > 0
? 1e8 - info.scoreMate
: -1e8 - info.scoreMate
: undefined;
if (score !== undefined) {
if (score < maxScore - maxScoreDiff) {
Expand All @@ -487,14 +487,14 @@ class Store {
maxScore = score;
}
}
const usi = iteration.pv[0];
const usi = info.pv[0];
if (usiSet.has(usi)) {
continue;
}
if (iteration.position !== sfen) {
if (info.position !== sfen) {
continue;
}
const pos = Position.newBySFEN(iteration.position);
const pos = Position.newBySFEN(info.position);
if (!pos) {
continue;
}
Expand Down Expand Up @@ -530,8 +530,8 @@ class Store {
this.researchManager.setMultiPV(sessionID, multiPV);
}

endUSIInfoIteration(sessionID: number, position: ImmutablePosition): void {
this.usiMonitor.endIteration(sessionID, position);
endUSIIteration(sessionID: number): void {
this.usiMonitor.endIteration(sessionID);
}

updateUSIInfo(
Expand Down
84 changes: 43 additions & 41 deletions src/renderer/store/usi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { USIInfoCommand } from "@/common/game/usi";
import { Color, ImmutablePosition, Move, Position, formatMove } from "tsshogi";
import { isActiveUSIPlayerSession } from "@/renderer/players/usi";

export type USIIteration = {
export type USIInfo = {
id: number;
position: string;
color: Color;
Expand Down Expand Up @@ -42,13 +42,13 @@ function formatPV(position: ImmutablePosition, pv: string[], maxLength: number):
return result;
}

let nextIterationID = 0;
let nextInfoID = 0;

export class USIPlayerMonitor {
public sfen = "";
public nodes?: number;
public nps?: number;
public iterations: USIIteration[] = [];
public infoList: USIInfo[] = [];
public hashfull?: number;
public currentMove?: string;
public currentMoveText?: string;
Expand All @@ -61,22 +61,22 @@ export class USIPlayerMonitor {
) {}

/**
* Returns latest iteration group.
* Returns latest info group.
*/
get latestIteration(): USIIteration[] {
const result: USIIteration[] = [];
get latestInfo(): USIInfo[] {
const result: USIInfo[] = [];
const multiPVSet = new Set();
const moveSet = new Set();
for (const iteration of this.iterations) {
const move = iteration.pv ? iteration.pv[0] : undefined;
for (const info of this.infoList) {
const move = info.pv ? info.pv[0] : undefined;
// Break if the same multiPV index is found twice.
if (move && multiPVSet.has(iteration.multiPV)) {
if (move && multiPVSet.has(info.multiPV)) {
break;
}
multiPVSet.add(iteration.multiPV);
// Add the iteration if not already added.
multiPVSet.add(info.multiPV);
// Add the info if not already added.
if (!moveSet.has(move)) {
result.push(iteration);
result.push(info);
moveSet.add(move);
}
}
Expand All @@ -90,7 +90,7 @@ export class USIPlayerMonitor {
this.sfen = sfen;
this.nodes = undefined;
this.nps = undefined;
this.iterations = [];
this.infoList = [];
this.hashfull = undefined;
this.currentMove = undefined;
this.currentMoveText = undefined;
Expand All @@ -101,41 +101,42 @@ export class USIPlayerMonitor {
if (!position) {
return;
}
const iteration: USIIteration = {
id: nextIterationID++,
const info: USIInfo = {
id: nextInfoID++,
position: sfen,
color: position.color,
};
const baseInfoKeyCount = 3;
if (update.depth !== undefined) {
iteration.depth = update.depth;
info.depth = update.depth;
}
if (update.seldepth !== undefined) {
iteration.selectiveDepth = update.seldepth;
info.selectiveDepth = update.seldepth;

Check warning on line 114 in src/renderer/store/usi.ts

View check run for this annotation

Codecov / codecov/patch

src/renderer/store/usi.ts#L114

Added line #L114 was not covered by tests
}
if (update.timeMs !== undefined) {
iteration.timeMs = update.timeMs;
info.timeMs = update.timeMs;

Check warning on line 117 in src/renderer/store/usi.ts

View check run for this annotation

Codecov / codecov/patch

src/renderer/store/usi.ts#L117

Added line #L117 was not covered by tests
}
if (update.nodes !== undefined) {
this.nodes = update.nodes;
}
if (update.pv) {
iteration.pv = update.pv;
iteration.text = formatPV(position, update.pv, maxPVTextLength);
info.pv = update.pv;
info.text = formatPV(position, update.pv, maxPVTextLength);
}
if (update.multipv !== undefined) {
iteration.multiPV = update.multipv;
info.multiPV = update.multipv;
}
if (update.scoreCP !== undefined) {
iteration.score = update.scoreCP;
info.score = update.scoreCP;
}
if (update.scoreMate !== undefined) {
iteration.scoreMate = update.scoreMate;
info.scoreMate = update.scoreMate;
}
if (update.lowerbound !== undefined) {
iteration.lowerBound = update.lowerbound;
info.lowerBound = update.lowerbound;

Check warning on line 136 in src/renderer/store/usi.ts

View check run for this annotation

Codecov / codecov/patch

src/renderer/store/usi.ts#L136

Added line #L136 was not covered by tests
}
if (update.upperbound !== undefined) {
iteration.upperBound = update.upperbound;
info.upperBound = update.upperbound;

Check warning on line 139 in src/renderer/store/usi.ts

View check run for this annotation

Codecov / codecov/patch

src/renderer/store/usi.ts#L139

Added line #L139 was not covered by tests
}
if (update.currmove !== undefined) {
this.currentMove = update.currmove;
Expand All @@ -151,23 +152,25 @@ export class USIPlayerMonitor {
this.nps = update.nps;
}
if (update.string) {
iteration.text = update.string;
}
if (Object.keys(iteration).length !== 0) {
// USI プロトコルにおいて nodes は読み筋と関係なく定期的に送る事ができるとされている。
// ただ、多くのエンジンが読み筋と一緒に送ってくるため読み筋等がある場合にはそちらにも記録する。
if (update.nodes !== undefined) {
iteration.nodes = update.nodes;
}
this.iterations.unshift(iteration);
info.text = update.string;

Check warning on line 155 in src/renderer/store/usi.ts

View check run for this annotation

Codecov / codecov/patch

src/renderer/store/usi.ts#L155

Added line #L155 was not covered by tests
}
this.ponderMove = ponderMove && formatMove(position, ponderMove);
}

endIteration(sfen: string) {
if (this.sfen === sfen) {
this.refreshOnNextUpdate = true;
// 要素が何もない場合はリストに登録しない。
if (Object.keys(info).length === baseInfoKeyCount) {
return;

Check warning on line 161 in src/renderer/store/usi.ts

View check run for this annotation

Codecov / codecov/patch

src/renderer/store/usi.ts#L161

Added line #L161 was not covered by tests
}
// USI プロトコルにおいて nodes は読み筋と関係なく定期的に送る事ができるとされている。
// ただ、多くのエンジンが読み筋と一緒に送ってくるため読み筋等がある場合にはそちらにも記録する。
if (update.nodes !== undefined) {
info.nodes = update.nodes;
}

Check warning on line 167 in src/renderer/store/usi.ts

View check run for this annotation

Codecov / codecov/patch

src/renderer/store/usi.ts#L166-L167

Added lines #L166 - L167 were not covered by tests

this.infoList.unshift(info);
}

endIteration() {
this.refreshOnNextUpdate = true;
}
}

Expand Down Expand Up @@ -249,14 +252,13 @@ export class USIMonitor {
return monitor;
}

endIteration(sessionID: number, position: ImmutablePosition) {
endIteration(sessionID: number) {
const monitor = this._sessions.find((session) => session.sessionID === sessionID);
if (monitor) {
const sfen = position.sfen;
// Invoke asynchronously to prevent IPC message delay.
setTimeout(() => {
this.dequeue(); // flush the queue
monitor.endIteration(sfen);
monitor.endIteration();
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/view/tab/EngineAnalytics.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
v-for="monitor in monitors"
:key="monitor.sessionID"
:history-mode="historyMode"
:info="monitor"
:monitor="monitor"
:height="elementHeight"
:show-header="showHeader"
:show-time-column="showTimeColumn"
Expand Down
Loading

0 comments on commit fb48813

Please sign in to comment.