feat : add move classification icons

This commit is contained in:
GuillaumeSD
2024-03-07 00:28:32 +01:00
parent c93983fa1f
commit 99a90def9c
23 changed files with 170 additions and 122 deletions

View File

@@ -1,7 +1,11 @@
import { Box, Grid, Typography } from "@mui/material";
import { useAtomValue } from "jotai";
import { useEffect, useState } from "react";
import { boardAtom, boardOrientationAtom, currentMoveAtom } from "../states";
import {
boardAtom,
boardOrientationAtom,
currentPositionAtom,
} from "../states";
import { getEvaluationBarValue } from "@/lib/chess";
interface Props {
@@ -15,17 +19,17 @@ export default function EvaluationBar({ height }: Props) {
});
const board = useAtomValue(boardAtom);
const boardOrientation = useAtomValue(boardOrientationAtom);
const currentMove = useAtomValue(currentMoveAtom);
const position = useAtomValue(currentPositionAtom);
const isWhiteToPlay = board.turn() === "w";
useEffect(() => {
const bestLine = currentMove?.eval?.lines[0];
const bestLine = position?.eval?.lines[0];
if (!bestLine || bestLine.depth < 6) return;
const evalBar = getEvaluationBarValue(bestLine, isWhiteToPlay);
setEvalBar(evalBar);
}, [currentMove, isWhiteToPlay]);
}, [position, isWhiteToPlay]);
return (
<Grid

View File

@@ -4,9 +4,8 @@ import { useAtomValue } from "jotai";
import {
boardAtom,
boardOrientationAtom,
currentMoveAtom,
currentPositionAtom,
showBestMoveArrowAtom,
showPlayerMoveArrowAtom,
} from "../states";
import { Arrow, Square } from "react-chessboard/dist/chessboard/types";
import { useChessActions } from "@/hooks/useChessActions";
@@ -15,6 +14,10 @@ import PlayerInfo from "./playerInfo";
import EvaluationBar from "./evaluationBar";
import { useScreenSize } from "@/hooks/useScreenSize";
import { MoveClassification } from "@/types/enums";
import {
moveClassificationColors,
useSquareRenderer,
} from "@/hooks/useSquareRenderer";
export default function Board() {
const boardRef = useRef<HTMLDivElement>(null);
@@ -22,9 +25,9 @@ export default function Board() {
const board = useAtomValue(boardAtom);
const boardOrientation = useAtomValue(boardOrientationAtom);
const showBestMoveArrow = useAtomValue(showBestMoveArrowAtom);
const showPlayerMoveArrow = useAtomValue(showPlayerMoveArrowAtom);
const { makeMove: makeBoardMove } = useChessActions(boardAtom);
const currentMove = useAtomValue(currentMoveAtom);
const position = useAtomValue(currentPositionAtom);
const squareRenderer = useSquareRenderer(position);
const onPieceDrop = (
source: Square,
@@ -45,9 +48,8 @@ export default function Board() {
};
const customArrows: Arrow[] = useMemo(() => {
const arrows: Arrow[] = [];
const bestMove = currentMove?.lastEval?.bestMove;
const moveClassification = currentMove?.eval?.moveClassification;
const bestMove = position?.lastEval?.bestMove;
const moveClassification = position?.eval?.moveClassification;
if (
bestMove &&
@@ -60,36 +62,11 @@ export default function Board() {
moveClassificationColors[MoveClassification.Best],
] as Arrow;
arrows.push(bestMoveArrow);
return [bestMoveArrow];
}
if (
currentMove.from &&
currentMove.to &&
showPlayerMoveArrow &&
moveClassification !== MoveClassification.Best
) {
const arrowColor = moveClassification
? moveClassificationColors[moveClassification]
: "#ffaa00";
const playerMoveArrow: Arrow = [
currentMove.from,
currentMove.to,
arrowColor,
];
if (
arrows.every(
(arrow) =>
arrow[0] !== playerMoveArrow[0] || arrow[1] !== playerMoveArrow[1]
)
) {
arrows.push(playerMoveArrow);
}
}
return arrows;
}, [currentMove, showBestMoveArrow, showPlayerMoveArrow]);
return [];
}, [position, showBestMoveArrow]);
return (
<Grid
@@ -131,6 +108,7 @@ export default function Board() {
borderRadius: "5px",
boxShadow: "0 2px 10px rgba(0, 0, 0, 0.5)",
}}
customSquare={squareRenderer}
/>
</Grid>
@@ -139,13 +117,3 @@ export default function Board() {
</Grid>
);
}
const moveClassificationColors: Record<MoveClassification, string> = {
[MoveClassification.Best]: "#26c2a3",
[MoveClassification.Book]: "#d5a47d",
[MoveClassification.Excellent]: "#3aab18",
[MoveClassification.Good]: "#81b64c",
[MoveClassification.Inaccuracy]: "#f7c631",
[MoveClassification.Mistake]: "#ffa459",
[MoveClassification.Blunder]: "#fa412d",
};

View File

@@ -3,7 +3,7 @@ import { Grid, List, Typography } from "@mui/material";
import { useAtomValue } from "jotai";
import { boardAtom, engineMultiPvAtom, gameAtom } from "../states";
import LineEvaluation from "./lineEvaluation";
import { useCurrentMove } from "@/hooks/useCurrentMove";
import { useCurrentPosition } from "@/hooks/useCurrentPosition";
import { LineEval } from "@/types/eval";
import { EngineName } from "@/types/enums";
import EngineSettingsButton from "@/sections/engineSettings/engineSettingsButton";
@@ -13,7 +13,7 @@ import Opening from "./opening";
export default function ReviewPanelBody() {
const linesNumber = useAtomValue(engineMultiPvAtom);
const move = useCurrentMove(EngineName.Stockfish16);
const position = useCurrentPosition(EngineName.Stockfish16);
const game = useAtomValue(gameAtom);
const board = useAtomValue(boardAtom);
@@ -30,8 +30,8 @@ export default function ReviewPanelBody() {
(_, i) => ({ pv: [`${i}`], depth: 0, multiPv: i + 1 })
);
const engineLines = move?.eval?.lines?.length
? move.eval.lines
const engineLines = position?.eval?.lines?.length
? position.eval.lines
: linesSkeleton;
return (

View File

@@ -1,16 +1,15 @@
import { useCurrentMove } from "@/hooks/useCurrentMove";
import { Grid, Typography } from "@mui/material";
import { useAtomValue } from "jotai";
import { boardAtom } from "../states";
import { boardAtom, currentPositionAtom } from "../states";
import { useMemo } from "react";
import { moveLineUciToSan } from "@/lib/chess";
import { MoveClassification } from "@/types/enums";
export default function MoveInfo() {
const move = useCurrentMove();
const position = useAtomValue(currentPositionAtom);
const board = useAtomValue(boardAtom);
const bestMove = move?.lastEval?.bestMove;
const bestMove = position?.lastEval?.bestMove;
const bestMoveSan = useMemo(() => {
if (!bestMove) return undefined;
@@ -23,9 +22,9 @@ export default function MoveInfo() {
if (!bestMoveSan) return null;
const moveClassification = move.eval?.moveClassification;
const moveClassification = position.eval?.moveClassification;
const moveLabel = moveClassification
? `${move.san} is ${moveClassificationLabels[moveClassification]}`
? `${position.lastMove?.san} is ${moveClassificationLabels[moveClassification]}`
: null;
const bestMoveLabel =

View File

@@ -1,10 +1,10 @@
import { useCurrentMove } from "@/hooks/useCurrentMove";
import { useCurrentPosition } from "@/hooks/useCurrentPosition";
import { Grid, Typography } from "@mui/material";
export default function Opening() {
const move = useCurrentMove();
const position = useCurrentPosition();
const opening = move?.eval?.opening;
const opening = position?.eval?.opening;
if (!opening) return null;
return (

View File

@@ -1,15 +1,15 @@
import { CurrentMove, GameEval } from "@/types/eval";
import { CurrentPosition, GameEval } from "@/types/eval";
import { Chess } from "chess.js";
import { atom } from "jotai";
export const gameEvalAtom = atom<GameEval | undefined>(undefined);
export const gameAtom = atom(new Chess());
export const boardAtom = atom(new Chess());
export const currentMoveAtom = atom<CurrentMove>({});
export const currentPositionAtom = atom<CurrentPosition>({});
export const boardOrientationAtom = atom(true);
export const showBestMoveArrowAtom = atom(true);
export const showPlayerMoveArrowAtom = atom(true);
export const showPlayerMoveIconAtom = atom(true);
export const engineDepthAtom = atom(16);
export const engineMultiPvAtom = atom(3);