feat : add move classification icons
This commit is contained in:
@@ -1,19 +1,19 @@
|
||||
import {
|
||||
boardAtom,
|
||||
currentMoveAtom,
|
||||
currentPositionAtom,
|
||||
engineDepthAtom,
|
||||
engineMultiPvAtom,
|
||||
gameAtom,
|
||||
gameEvalAtom,
|
||||
} from "@/sections/analysis/states";
|
||||
import { CurrentMove, MoveEval } from "@/types/eval";
|
||||
import { CurrentPosition, PositionEval } from "@/types/eval";
|
||||
import { useAtom, useAtomValue } from "jotai";
|
||||
import { useEffect } from "react";
|
||||
import { useEngine } from "./useEngine";
|
||||
import { EngineName } from "@/types/enums";
|
||||
|
||||
export const useCurrentMove = (engineName?: EngineName) => {
|
||||
const [currentMove, setCurrentMove] = useAtom(currentMoveAtom);
|
||||
export const useCurrentPosition = (engineName?: EngineName) => {
|
||||
const [currentPosition, setCurrentPosition] = useAtom(currentPositionAtom);
|
||||
const engine = useEngine(engineName);
|
||||
const gameEval = useAtomValue(gameEvalAtom);
|
||||
const game = useAtomValue(gameAtom);
|
||||
@@ -22,8 +22,8 @@ export const useCurrentMove = (engineName?: EngineName) => {
|
||||
const multiPv = useAtomValue(engineMultiPvAtom);
|
||||
|
||||
useEffect(() => {
|
||||
const move: CurrentMove = {
|
||||
...board.history({ verbose: true }).at(-1),
|
||||
const position: CurrentPosition = {
|
||||
lastMove: board.history({ verbose: true }).at(-1),
|
||||
};
|
||||
|
||||
if (gameEval) {
|
||||
@@ -36,15 +36,15 @@ export const useCurrentMove = (engineName?: EngineName) => {
|
||||
) {
|
||||
const evalIndex = board.history().length;
|
||||
|
||||
move.eval = gameEval.moves[evalIndex];
|
||||
move.lastEval =
|
||||
evalIndex > 0 ? gameEval.moves[evalIndex - 1] : undefined;
|
||||
position.eval = gameEval.positions[evalIndex];
|
||||
position.lastEval =
|
||||
evalIndex > 0 ? gameEval.positions[evalIndex - 1] : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (!move.eval && engine?.isReady()) {
|
||||
const setPartialEval = (moveEval: MoveEval) => {
|
||||
setCurrentMove({ ...move, eval: moveEval });
|
||||
if (!position.eval && engine?.isReady()) {
|
||||
const setPartialEval = (positionEval: PositionEval) => {
|
||||
setCurrentPosition({ ...position, eval: positionEval });
|
||||
};
|
||||
|
||||
engine.evaluatePositionWithUpdate({
|
||||
@@ -55,8 +55,8 @@ export const useCurrentMove = (engineName?: EngineName) => {
|
||||
});
|
||||
}
|
||||
|
||||
setCurrentMove(move);
|
||||
}, [gameEval, board, game, engine, depth, multiPv, setCurrentMove]);
|
||||
setCurrentPosition(position);
|
||||
}, [gameEval, board, game, engine, depth, multiPv, setCurrentPosition]);
|
||||
|
||||
return currentMove;
|
||||
return currentPosition;
|
||||
};
|
||||
73
src/hooks/useSquareRenderer.tsx
Normal file
73
src/hooks/useSquareRenderer.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { showPlayerMoveIconAtom } from "@/sections/analysis/states";
|
||||
import { MoveClassification } from "@/types/enums";
|
||||
import { CurrentPosition } from "@/types/eval";
|
||||
import { useAtomValue } from "jotai";
|
||||
import Image from "next/image";
|
||||
import { CSSProperties, forwardRef, useMemo } from "react";
|
||||
import { CustomSquareProps } from "react-chessboard/dist/chessboard/types";
|
||||
|
||||
export const useSquareRenderer = (position: CurrentPosition) => {
|
||||
const showPlayerMoveIcon = useAtomValue(showPlayerMoveIconAtom);
|
||||
|
||||
const CustomSquareRenderer = useMemo(() => {
|
||||
const fromSquare = position.lastMove?.from;
|
||||
const toSquare = position.lastMove?.to;
|
||||
const moveClassification = position?.eval?.moveClassification;
|
||||
|
||||
if (!showPlayerMoveIcon || !moveClassification || !fromSquare || !toSquare)
|
||||
return undefined;
|
||||
|
||||
const squareRenderer = forwardRef<HTMLDivElement, CustomSquareProps>(
|
||||
(props, ref) => {
|
||||
const { children, square, style } = props;
|
||||
|
||||
const customSquareStyle: CSSProperties | undefined =
|
||||
fromSquare === square || toSquare === square
|
||||
? {
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: moveClassificationColors[moveClassification],
|
||||
opacity: 0.5,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div ref={ref} style={{ ...style, position: "relative" }}>
|
||||
{children}
|
||||
{customSquareStyle && <div style={customSquareStyle} />}
|
||||
{square === toSquare && (
|
||||
<Image
|
||||
src={`/icons/${moveClassification}.png`}
|
||||
alt="move-icon"
|
||||
width={40}
|
||||
height={40}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: -12,
|
||||
right: -12,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
squareRenderer.displayName = "CustomSquareRenderer";
|
||||
|
||||
return squareRenderer;
|
||||
}, [showPlayerMoveIcon, position]);
|
||||
|
||||
return CustomSquareRenderer;
|
||||
};
|
||||
|
||||
export const moveClassificationColors: Record<MoveClassification, string> = {
|
||||
[MoveClassification.Best]: "#3aab18",
|
||||
[MoveClassification.Book]: "#d5a47d",
|
||||
[MoveClassification.Excellent]: "#3aab18",
|
||||
[MoveClassification.Good]: "#81b64c",
|
||||
[MoveClassification.Inaccuracy]: "#f7c631",
|
||||
[MoveClassification.Mistake]: "#ffa459",
|
||||
[MoveClassification.Blunder]: "#fa412d",
|
||||
};
|
||||
Reference in New Issue
Block a user