From 892004f0d0cc7619c16533f63a1c173bfcdcb557 Mon Sep 17 00:00:00 2001 From: GuillaumeSD Date: Sun, 25 Feb 2024 00:35:02 +0100 Subject: [PATCH] feat : add evaluation bar --- src/hooks/useCurrentMove.ts | 4 +- src/hooks/useEngine.ts | 4 +- src/lib/chess.ts | 28 ++++++ src/pages/index.tsx | 11 ++- src/sections/analysis/board/evaluationBar.tsx | 86 +++++++++++++++++++ src/sections/analysis/board/index.tsx | 48 ++++++----- src/sections/analysis/reviewPanelBody.tsx | 3 +- 7 files changed, 158 insertions(+), 26 deletions(-) create mode 100644 src/sections/analysis/board/evaluationBar.tsx diff --git a/src/hooks/useCurrentMove.ts b/src/hooks/useCurrentMove.ts index 5383561..f4387ba 100644 --- a/src/hooks/useCurrentMove.ts +++ b/src/hooks/useCurrentMove.ts @@ -17,9 +17,9 @@ export type CurrentMove = Partial & { lastEval?: MoveEval; }; -export const useCurrentMove = () => { +export const useCurrentMove = (engineName?: EngineName) => { const [currentMove, setCurrentMove] = useState({}); - const engine = useEngine(EngineName.Stockfish16); + const engine = useEngine(engineName); const gameEval = useAtomValue(gameEvalAtom); const game = useAtomValue(gameAtom); const board = useAtomValue(boardAtom); diff --git a/src/hooks/useEngine.ts b/src/hooks/useEngine.ts index fd78acc..c0218f5 100644 --- a/src/hooks/useEngine.ts +++ b/src/hooks/useEngine.ts @@ -5,7 +5,7 @@ import { EngineName } from "@/types/enums"; import { useAtomValue } from "jotai"; import { useEffect, useState } from "react"; -export const useEngine = (engineName: EngineName) => { +export const useEngine = (engineName: EngineName | undefined) => { const [engine, setEngine] = useState(null); const multiPv = useAtomValue(engineMultiPvAtom); @@ -17,6 +17,8 @@ export const useEngine = (engineName: EngineName) => { }; useEffect(() => { + if (!engineName) return; + const engine = pickEngine(engineName); engine.init().then(() => { setEngine(engine); diff --git a/src/lib/chess.ts b/src/lib/chess.ts index 587b649..8a172d6 100644 --- a/src/lib/chess.ts +++ b/src/lib/chess.ts @@ -1,3 +1,4 @@ +import { LineEval } from "@/types/eval"; import { Game } from "@/types/game"; import { Chess } from "chess.js"; @@ -77,3 +78,30 @@ export const moveLineUciToSan = ( } }; }; + +export const getEvaluationBarValue = ( + bestLine: LineEval, + whiteToPlay: boolean +): { whiteBarPercentage: number; label: string } => { + if (bestLine.mate) { + return { + whiteBarPercentage: whiteToPlay ? 100 : 0, + label: `M${bestLine.mate}`, + }; + } + + if (!bestLine.cp) { + return { whiteBarPercentage: 50, label: "0.0" }; + } + + const cp = bestLine.cp; + const whiteBarPercentage = Math.min(50 + cp / 20, 98); + + const label = (cp / 100).toFixed(1); + + if (label.toString().length > 3) { + return { whiteBarPercentage, label: (cp / 100).toFixed(0) }; + } + + return { whiteBarPercentage, label: (cp / 100).toFixed(1) }; +}; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 913dc2a..8d1d3aa 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -40,7 +40,16 @@ export default function GameReport() { alignItems="center" marginTop={1} > - + + + { + const bestLine = currentMove?.eval?.lines[0]; + if (!bestLine) return; + + const evalBar = getEvaluationBarValue(bestLine, board.turn() === "w"); + setEvalBar(evalBar); + }, [currentMove, board.turn()]); + + return ( + + + + {(evalBar.whiteBarPercentage < 50 && boardOrientation) || + (evalBar.whiteBarPercentage >= 50 && !boardOrientation) + ? evalBar.label + : ""} + + + + + + {(evalBar.whiteBarPercentage >= 50 && boardOrientation) || + (evalBar.whiteBarPercentage < 50 && !boardOrientation) + ? evalBar.label + : ""} + + + + ); +} diff --git a/src/sections/analysis/board/index.tsx b/src/sections/analysis/board/index.tsx index 75d43ec..861d72f 100644 --- a/src/sections/analysis/board/index.tsx +++ b/src/sections/analysis/board/index.tsx @@ -10,10 +10,12 @@ import { import { Arrow, Square } from "react-chessboard/dist/chessboard/types"; import { useChessActions } from "@/hooks/useChess"; import { useCurrentMove } from "@/hooks/useCurrentMove"; -import { useMemo } from "react"; +import { useMemo, useRef } from "react"; import PlayerInfo from "./playerInfo"; +import EvaluationBar from "./evaluationBar"; export default function Board() { + const boardRef = useRef(null); const board = useAtomValue(boardAtom); const boardOrientation = useAtomValue(boardOrientationAtom); const showBestMoveArrow = useAtomValue(showBestMoveArrowAtom); @@ -69,34 +71,38 @@ export default function Board() { }, [currentMove, showBestMoveArrow, showPlayerMoveArrow]); return ( - - + + - - + - + + + + + + ); } diff --git a/src/sections/analysis/reviewPanelBody.tsx b/src/sections/analysis/reviewPanelBody.tsx index 0dbf8e5..a31bdc8 100644 --- a/src/sections/analysis/reviewPanelBody.tsx +++ b/src/sections/analysis/reviewPanelBody.tsx @@ -5,10 +5,11 @@ import { boardAtom, engineMultiPvAtom, gameAtom } from "./states"; import LineEvaluation from "./lineEvaluation"; import { useCurrentMove } from "@/hooks/useCurrentMove"; import { LineEval } from "@/types/eval"; +import { EngineName } from "@/types/enums"; export default function ReviewPanelBody() { const linesNumber = useAtomValue(engineMultiPvAtom); - const move = useCurrentMove(); + const move = useCurrentMove(EngineName.Stockfish16); const game = useAtomValue(gameAtom); const board = useAtomValue(boardAtom);