mirror of
https://github.com/lichess-org/lila.git
synced 2026-05-26 13:51:00 +00:00
refactor and simplify analysis ceval annotations
This commit is contained in:
@@ -177,7 +177,7 @@ export function compute(ctrl: AnalyseCtrl): DrawShape[] {
|
||||
});
|
||||
}
|
||||
if (ctrl.showMoveAnnotationsOnBoard()) {
|
||||
const liveGlyph = ctrl.liveGlyphs.get(ctrl.path);
|
||||
const liveGlyph = ctrl.liveAnnotate.get(ctrl.path);
|
||||
shapes = shapes.concat(
|
||||
// Override server analysis glyphs as local eval also overrides the eval score
|
||||
annotationShapes(liveGlyph ? { ...ctrl.node, glyphs: [liveGlyph] } : ctrl.node),
|
||||
|
||||
+5
-24
@@ -39,7 +39,7 @@ import { pubsub } from 'lib/pubsub';
|
||||
import { storedBooleanProp, storedBooleanPropWithEffect } from 'lib/storage';
|
||||
import { makeTree, treePath, treeOps, type TreeWrapper } from 'lib/tree';
|
||||
import { completeNode } from 'lib/tree/node';
|
||||
import type { ClientEval, Glyph, LocalEval, ServerEval, TreeNode, TreePath } from 'lib/tree/types';
|
||||
import type { ClientEval, LocalEval, ServerEval, TreeNode, TreePath } from 'lib/tree/types';
|
||||
import { confirm } from 'lib/view';
|
||||
|
||||
import { Autoplay, type AutoplayDelay } from './autoplay';
|
||||
@@ -52,7 +52,7 @@ import { ForkCtrl } from './fork';
|
||||
import { IdbTree } from './idbTree';
|
||||
import type { AnalyseOpts, AnalyseData, ServerEvalData, JustCaptured, NvuiPlugin } from './interfaces';
|
||||
import * as keyboard from './keyboard';
|
||||
import { liveNodeGlyph } from './liveAnnotate';
|
||||
import LiveAnnotate from './liveAnnotate';
|
||||
import MotifCtrl from './motif/motifCtrl';
|
||||
import Navigate from './navigate';
|
||||
import { nextGlyphSymbol, add3or5FoldGlyphs } from './nodeFinder';
|
||||
@@ -76,6 +76,7 @@ export default class AnalyseCtrl implements CevalHandler {
|
||||
chessground: ChessgroundApi;
|
||||
ceval: CevalCtrl;
|
||||
evalCache: EvalCache;
|
||||
liveAnnotate: LiveAnnotate;
|
||||
navigate: Navigate;
|
||||
idbTree: IdbTree = new IdbTree(this);
|
||||
actionMenu: Toggle = toggle(false);
|
||||
@@ -123,7 +124,6 @@ export default class AnalyseCtrl implements CevalHandler {
|
||||
);
|
||||
showFishnetAnalysis = storedBooleanProp('analyse.show-computer', true);
|
||||
possiblyShowMoveAnnotationsOnBoard = storedBooleanProp('analyse.show-move-annotation', true);
|
||||
liveGlyphs = new Map<TreePath, Glyph | undefined>();
|
||||
keyboardHelp: boolean = location.hash === '#keyboard';
|
||||
threatMode: Prop<boolean> = prop(false);
|
||||
disclosureMode = storedBooleanProp('analyse.disclosure.enabled', false);
|
||||
@@ -179,6 +179,7 @@ export default class AnalyseCtrl implements CevalHandler {
|
||||
});
|
||||
|
||||
this.instanciateEvalCache();
|
||||
this.liveAnnotate = new LiveAnnotate();
|
||||
|
||||
if (opts.inlinePgn) this.data = this.changePgn(opts.inlinePgn, false) || this.data;
|
||||
|
||||
@@ -740,10 +741,7 @@ export default class AnalyseCtrl implements CevalHandler {
|
||||
if (node.ceval?.cloud && this.ceval.isDeeper()) node.ceval = ev;
|
||||
}
|
||||
|
||||
if (!isThreat && ev) {
|
||||
this.annotateLivePath(path);
|
||||
this.annotateLiveChildren(path, node);
|
||||
}
|
||||
if (!isThreat) this.liveAnnotate.onNewCeval(path, node, this.tree);
|
||||
|
||||
if (path === this.path) {
|
||||
this.setAutoShapes();
|
||||
@@ -759,23 +757,6 @@ export default class AnalyseCtrl implements CevalHandler {
|
||||
});
|
||||
};
|
||||
|
||||
private annotateLivePath(path: TreePath): void {
|
||||
if (path.length)
|
||||
this.liveGlyphs.set(path, liveNodeGlyph(this.tree.nodeAtPath(path), this.tree.parentNode(path)));
|
||||
}
|
||||
|
||||
private annotateLiveChildren(path: TreePath, node: TreeNode): void {
|
||||
node.children.forEach(child => this.annotateLivePath(path + child.id));
|
||||
}
|
||||
|
||||
private rebuildLiveGlyphs(node = this.tree.root, path: TreePath = treePath.root): void {
|
||||
node.children.forEach(child => {
|
||||
const childPath = path + child.id;
|
||||
this.annotateLivePath(childPath);
|
||||
this.rebuildLiveGlyphs(child, childPath);
|
||||
});
|
||||
}
|
||||
|
||||
private initCeval(): void {
|
||||
const opts: CevalOpts = {
|
||||
variant: this.data.game.variant,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { povChances } from 'lib/ceval/winningChances';
|
||||
import type { Glyph, TreeNode } from 'lib/tree/types';
|
||||
import type { TreeWrapper } from 'lib/tree';
|
||||
import type { Glyph, TreeNode, TreePath } from 'lib/tree/types';
|
||||
|
||||
const glyphs = {
|
||||
inaccuracy: { id: 6, symbol: '?!', name: 'Inaccuracy' } as Glyph,
|
||||
@@ -7,15 +8,34 @@ const glyphs = {
|
||||
blunder: { id: 4, symbol: '??', name: 'Blunder' } as Glyph,
|
||||
};
|
||||
|
||||
export function liveGlyph(parentEval: EvalScore, currentEval: EvalScore, ply: Ply): Glyph | undefined {
|
||||
const color: Color = ply % 2 === 1 ? 'white' : 'black';
|
||||
const loss = povChances(color, parentEval) - povChances(color, currentEval);
|
||||
if (loss > 0.3) return glyphs.blunder;
|
||||
if (loss > 0.2) return glyphs.mistake;
|
||||
if (loss > 0.1) return glyphs.inaccuracy;
|
||||
return undefined;
|
||||
}
|
||||
export default class LiveAnnotate {
|
||||
private readonly glyphs = new Map<TreePath, Glyph>();
|
||||
|
||||
export function liveNodeGlyph(node: TreeNode, parentNode: TreeNode): Glyph | undefined {
|
||||
return parentNode.ceval && node.ceval && liveGlyph(parentNode.ceval, node.ceval, node.ply);
|
||||
readonly get = this.glyphs.get.bind(this.glyphs);
|
||||
|
||||
readonly onNewCeval = (path: TreePath, node: TreeNode, tree: TreeWrapper): void => {
|
||||
const parent = tree.parentNode(path);
|
||||
this.update(path, node, parent);
|
||||
node.children.forEach(child => this.update(path + child.id, child, node));
|
||||
};
|
||||
|
||||
private readonly liveGlyph = (
|
||||
parentEval: EvalScore,
|
||||
currentEval: EvalScore,
|
||||
ply: Ply,
|
||||
): Glyph | undefined => {
|
||||
const color: Color = ply % 2 === 1 ? 'white' : 'black';
|
||||
const loss = povChances(color, parentEval) - povChances(color, currentEval);
|
||||
if (loss > 0.3) return glyphs.blunder;
|
||||
if (loss > 0.2) return glyphs.mistake;
|
||||
if (loss > 0.1) return glyphs.inaccuracy;
|
||||
return undefined;
|
||||
};
|
||||
|
||||
private readonly update = (path: TreePath, node: TreeNode, parent: TreeNode): void => {
|
||||
if (!path.length) return;
|
||||
const glyph = parent.ceval && node.ceval && this.liveGlyph(parent.ceval, node.ceval, node.ply);
|
||||
if (glyph) this.glyphs.set(path, glyph);
|
||||
else this.glyphs.delete(path);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ export class InlineView {
|
||||
'pending-deletion': path.startsWith(ctrl.pendingDeletionPath() || ' '),
|
||||
'pending-copy': !!ctrl.pendingCopyPath()?.startsWith(path),
|
||||
};
|
||||
const liveGlyph = ctrl.liveGlyphs.get(path);
|
||||
const liveGlyph = ctrl.liveAnnotate.get(path);
|
||||
const glyphs = liveGlyph ? [liveGlyph] : node.glyphs;
|
||||
if (ctrl.showMoveGlyphs()) {
|
||||
glyphs
|
||||
|
||||
Reference in New Issue
Block a user