feat : add progress bar

This commit is contained in:
GuillaumeSD
2024-03-08 23:56:29 +01:00
parent 91b56fde60
commit 81cbc2ca80
7 changed files with 72 additions and 27 deletions

View File

@@ -0,0 +1,39 @@
import {
Grid,
LinearProgress,
LinearProgressProps,
Typography,
} from "@mui/material";
const LinearProgressBar = (
props: LinearProgressProps & { value: number; label: string }
) => {
if (props.value === 0) return null;
return (
<Grid item container alignItems="center" justifyContent="center" xs={12}>
<Typography variant="caption" align="center">
{props.label}
</Typography>
<Grid
item
container
xs={12}
alignItems="center"
justifyContent="center"
wrap="nowrap"
>
<Grid item sx={{ width: "100%", mr: 2 }}>
<LinearProgress variant="determinate" {...props} />
</Grid>
<Grid item sx={{ minWidth: 35 }}>
<Typography variant="body2" color="text.secondary">{`${Math.round(
props.value
)}%`}</Typography>
</Grid>
</Grid>
</Grid>
);
};
export default LinearProgressBar;

View File

@@ -100,8 +100,10 @@ export abstract class UciEngine {
uciMoves,
depth = 16,
multiPv = this.multiPv,
setEvaluationProgress,
}: EvaluateGameParams): Promise<GameEval> {
this.throwErrorIfNotReady();
setEvaluationProgress?.(1);
await this.setMultiPv(multiPv);
this.ready = false;
@@ -126,6 +128,9 @@ export abstract class UciEngine {
}
const result = await this.evaluatePosition(fen, depth);
positions.push(result);
setEvaluationProgress?.(
Math.max((fens.indexOf(fen) / fens.length) * 100 - 5, 2)
);
}
const positionsWithClassification = getMovesClassification(
@@ -136,6 +141,7 @@ export abstract class UciEngine {
const accuracy = computeAccuracy(positions);
this.ready = true;
setEvaluationProgress?.(99);
return {
positions: positionsWithClassification,
accuracy,

View File

@@ -1,12 +1,12 @@
import { Icon } from "@iconify/react";
import { useState } from "react";
import {
engineDepthAtom,
engineMultiPvAtom,
evaluationProgressAtom,
gameAtom,
gameEvalAtom,
} from "../states";
import { useAtomValue, useSetAtom } from "jotai";
import { useAtom, useAtomValue } from "jotai";
import { getEvaluateGameParams } from "@/lib/chess";
import { useGameDatabase } from "@/hooks/useGameDatabase";
import { LoadingButton } from "@mui/lab";
@@ -16,36 +16,33 @@ import { logAnalyticsEvent } from "@/lib/firebase";
export default function AnalyzeButton() {
const engine = useEngine(EngineName.Stockfish16);
const [evaluationInProgress, setEvaluationInProgress] = useState(false);
const [evaluationProgress, setEvaluationProgress] = useAtom(
evaluationProgressAtom
);
const engineDepth = useAtomValue(engineDepthAtom);
const engineMultiPv = useAtomValue(engineMultiPvAtom);
const { setGameEval, gameFromUrl } = useGameDatabase();
const setEval = useSetAtom(gameEvalAtom);
const [gameEval, setEval] = useAtom(gameEvalAtom);
const game = useAtomValue(gameAtom);
const readyToAnalyse =
engine?.isReady() && game.history().length > 0 && !evaluationInProgress;
engine?.isReady() && game.history().length > 0 && !evaluationProgress;
const handleAnalyze = async () => {
const params = getEvaluateGameParams(game);
if (
!engine?.isReady() ||
params.fens.length === 0 ||
evaluationInProgress
) {
if (!engine?.isReady() || params.fens.length === 0 || evaluationProgress) {
return;
}
setEvaluationInProgress(true);
const newGameEval = await engine.evaluateGame({
...params,
depth: engineDepth,
multiPv: engineMultiPv,
setEvaluationProgress,
});
setEval(newGameEval);
setEvaluationInProgress(false);
setEvaluationProgress(0);
if (gameFromUrl) {
setGameEval(gameFromUrl.id, newGameEval);
@@ -59,26 +56,17 @@ export default function AnalyzeButton() {
});
};
if (evaluationProgress) return null;
return (
<LoadingButton
variant="contained"
size="small"
startIcon={
!evaluationInProgress && (
<Icon icon="streamline:magnifying-glass-solid" />
)
}
startIcon={<Icon icon="streamline:magnifying-glass-solid" />}
onClick={handleAnalyze}
disabled={!readyToAnalyse}
loading={evaluationInProgress}
loadingPosition={evaluationInProgress ? "end" : undefined}
endIcon={
evaluationInProgress && (
<Icon icon="streamline:magnifying-glass-solid" />
)
}
>
{evaluationInProgress ? "Analyzing..." : "Analyze"}
{gameEval ? "Analyze again" : "Analyze"}
</LoadingButton>
);
}

View File

@@ -3,8 +3,13 @@ import { Grid, Typography } from "@mui/material";
import GamePanel from "./gamePanel";
import LoadGame from "./loadGame";
import AnalyzeButton from "./analyzeButton";
import LinearProgressBar from "@/components/LinearProgressBar";
import { useAtomValue } from "jotai";
import { evaluationProgressAtom } from "../states";
export default function ReviewPanelHeader() {
const evaluationProgress = useAtomValue(evaluationProgressAtom);
return (
<Grid
item
@@ -36,11 +41,12 @@ export default function ReviewPanelHeader() {
justifyContent="center"
alignItems="center"
rowGap={3}
columnGap={15}
columnGap={12}
>
<GamePanel />
<LoadGame />
<AnalyzeButton />
<LinearProgressBar value={evaluationProgress} label="Analyzing..." />
</Grid>
</Grid>
);

View File

@@ -4,6 +4,7 @@ import { useChessActions } from "@/hooks/useChessActions";
import {
boardAtom,
boardOrientationAtom,
evaluationProgressAtom,
gameAtom,
gameEvalAtom,
} from "../states";
@@ -20,6 +21,7 @@ export default function LoadGame() {
const { gameFromUrl } = useGameDatabase();
const setEval = useSetAtom(gameEvalAtom);
const setBoardOrientation = useSetAtom(boardOrientationAtom);
const evaluationProgress = useAtomValue(evaluationProgressAtom);
const resetAndSetGamePgn = useCallback(
(pgn: string) => {
@@ -48,6 +50,8 @@ export default function LoadGame() {
const isGameLoaded = gameFromUrl !== undefined || !!game.header().White;
if (evaluationProgress) return null;
return (
<LoadGameButton
label={isGameLoaded ? "Load another game" : "Load game"}

View File

@@ -13,3 +13,4 @@ export const showPlayerMoveIconAtom = atom(true);
export const engineDepthAtom = atom(16);
export const engineMultiPvAtom = atom(3);
export const evaluationProgressAtom = atom(0);

View File

@@ -52,4 +52,5 @@ export interface EvaluateGameParams {
uciMoves: string[];
depth?: number;
multiPv?: number;
setEvaluationProgress?: (value: number) => void;
}