feat : add move classification icons
BIN
public/icons/best.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
public/icons/blunder.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/icons/book.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/icons/excellent.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/icons/good.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
public/icons/inaccuracy.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/icons/mistake.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
@@ -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
@@ -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",
|
||||
};
|
||||
@@ -4,15 +4,15 @@ import {
|
||||
getStandardDeviation,
|
||||
getWeightedMean,
|
||||
} from "@/lib/helpers";
|
||||
import { Accuracy, MoveEval } from "@/types/eval";
|
||||
import { Accuracy, PositionEval } from "@/types/eval";
|
||||
import { getPositionWinPercentage } from "./winPercentage";
|
||||
|
||||
export const computeAccuracy = (moves: MoveEval[]): Accuracy => {
|
||||
const movesWinPercentage = moves.map(getPositionWinPercentage);
|
||||
export const computeAccuracy = (positions: PositionEval[]): Accuracy => {
|
||||
const positionsWinPercentage = positions.map(getPositionWinPercentage);
|
||||
|
||||
const weights = getAccuracyWeights(movesWinPercentage);
|
||||
const weights = getAccuracyWeights(positionsWinPercentage);
|
||||
|
||||
const movesAccuracy = getMovesAccuracy(movesWinPercentage);
|
||||
const movesAccuracy = getMovesAccuracy(positionsWinPercentage);
|
||||
|
||||
const whiteAccuracy = getPlayerAccuracy(movesAccuracy, weights, "white");
|
||||
const blackAccuracy = getPlayerAccuracy(movesAccuracy, weights, "black");
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { MoveEval } from "@/types/eval";
|
||||
import { PositionEval } from "@/types/eval";
|
||||
import { getPositionWinPercentage } from "./winPercentage";
|
||||
import { MoveClassification } from "@/types/enums";
|
||||
import { openings } from "@/data/openings";
|
||||
|
||||
export const getMovesClassification = (
|
||||
rawMoves: MoveEval[],
|
||||
rawMoves: PositionEval[],
|
||||
uciMoves: string[],
|
||||
fens: string[]
|
||||
): MoveEval[] => {
|
||||
): PositionEval[] => {
|
||||
const positionsWinPercentage = rawMoves.map(getPositionWinPercentage);
|
||||
let currentOpening: string | undefined = undefined;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { LineEval, MoveEval } from "@/types/eval";
|
||||
import { LineEval, PositionEval } from "@/types/eval";
|
||||
|
||||
export const parseEvaluationResults = (
|
||||
results: string[],
|
||||
whiteToPlay: boolean
|
||||
): MoveEval => {
|
||||
const parsedResults: MoveEval = {
|
||||
): PositionEval => {
|
||||
const parsedResults: PositionEval = {
|
||||
lines: [],
|
||||
};
|
||||
const tempResults: Record<string, LineEval> = {};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { ceilsNumber } from "@/lib/helpers";
|
||||
import { MoveEval } from "@/types/eval";
|
||||
import { PositionEval } from "@/types/eval";
|
||||
|
||||
export const getPositionWinPercentage = (move: MoveEval): number => {
|
||||
if (move.lines[0].cp !== undefined) {
|
||||
return getWinPercentageFromCp(move.lines[0].cp);
|
||||
export const getPositionWinPercentage = (position: PositionEval): number => {
|
||||
if (position.lines[0].cp !== undefined) {
|
||||
return getWinPercentageFromCp(position.lines[0].cp);
|
||||
}
|
||||
|
||||
if (move.lines[0].mate !== undefined) {
|
||||
return getWinPercentageFromMate(move.lines[0].mate);
|
||||
if (position.lines[0].mate !== undefined) {
|
||||
return getWinPercentageFromMate(position.lines[0].mate);
|
||||
}
|
||||
|
||||
throw new Error("No cp or mate in move");
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
EvaluateGameParams,
|
||||
EvaluatePositionWithUpdateParams,
|
||||
GameEval,
|
||||
MoveEval,
|
||||
PositionEval,
|
||||
} from "@/types/eval";
|
||||
import { parseEvaluationResults } from "./helpers/parseResults";
|
||||
import { computeAccuracy } from "./helpers/accuracy";
|
||||
@@ -108,11 +108,11 @@ export abstract class UciEngine {
|
||||
await this.sendCommands(["ucinewgame", "isready"], "readyok");
|
||||
this.worker.postMessage("position startpos");
|
||||
|
||||
const moves: MoveEval[] = [];
|
||||
const positions: PositionEval[] = [];
|
||||
for (const fen of fens) {
|
||||
const whoIsCheckmated = getWhoIsCheckmated(fen);
|
||||
if (whoIsCheckmated) {
|
||||
moves.push({
|
||||
positions.push({
|
||||
lines: [
|
||||
{
|
||||
pv: [],
|
||||
@@ -125,19 +125,19 @@ export abstract class UciEngine {
|
||||
continue;
|
||||
}
|
||||
const result = await this.evaluatePosition(fen, depth);
|
||||
moves.push(result);
|
||||
positions.push(result);
|
||||
}
|
||||
|
||||
const movesWithClassification = getMovesClassification(
|
||||
moves,
|
||||
const positionsWithClassification = getMovesClassification(
|
||||
positions,
|
||||
uciMoves,
|
||||
fens
|
||||
);
|
||||
const accuracy = computeAccuracy(moves);
|
||||
const accuracy = computeAccuracy(positions);
|
||||
|
||||
this.ready = true;
|
||||
return {
|
||||
moves: movesWithClassification,
|
||||
positions: positionsWithClassification,
|
||||
accuracy,
|
||||
settings: {
|
||||
engine: this.engineName,
|
||||
@@ -148,7 +148,10 @@ export abstract class UciEngine {
|
||||
};
|
||||
}
|
||||
|
||||
private async evaluatePosition(fen: string, depth = 16): Promise<MoveEval> {
|
||||
private async evaluatePosition(
|
||||
fen: string,
|
||||
depth = 16
|
||||
): Promise<PositionEval> {
|
||||
console.log(`Evaluating position: ${fen}`);
|
||||
|
||||
const lichessEval = await getLichessEval(fen, this.multiPv);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LineEval, MoveEval } from "@/types/eval";
|
||||
import { LineEval, PositionEval } from "@/types/eval";
|
||||
import { sortLines } from "./engine/helpers/parseResults";
|
||||
import {
|
||||
LichessError,
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
export const getLichessEval = async (
|
||||
fen: string,
|
||||
multiPv = 1
|
||||
): Promise<MoveEval> => {
|
||||
): Promise<PositionEval> => {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`https://lichess.org/api/cloud-eval?fen=${fen}&multiPv=${multiPv}`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Checkbox, FormControlLabel, Grid } from "@mui/material";
|
||||
import {
|
||||
showBestMoveArrowAtom,
|
||||
showPlayerMoveArrowAtom,
|
||||
showPlayerMoveIconAtom,
|
||||
} from "../analysis/states";
|
||||
import { useAtomLocalStorage } from "@/hooks/useAtomLocalStorage";
|
||||
|
||||
@@ -10,9 +10,9 @@ export default function ArrowOptions() {
|
||||
"show-arrow-best-move",
|
||||
showBestMoveArrowAtom
|
||||
);
|
||||
const [showPlayerMove, setShowPlayerMove] = useAtomLocalStorage(
|
||||
"show-arrow-player-move",
|
||||
showPlayerMoveArrowAtom
|
||||
const [showPlayerMoveIcon, setShowPlayerMoveIcon] = useAtomLocalStorage(
|
||||
"show-icon-player-move",
|
||||
showPlayerMoveIconAtom
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -37,11 +37,11 @@ export default function ArrowOptions() {
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={showPlayerMove}
|
||||
onChange={(_, checked) => setShowPlayerMove(checked)}
|
||||
checked={showPlayerMoveIcon}
|
||||
onChange={(_, checked) => setShowPlayerMoveIcon(checked)}
|
||||
/>
|
||||
}
|
||||
label="Show played move arrow"
|
||||
label="Show played move icon"
|
||||
sx={{ marginX: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Move } from "chess.js";
|
||||
import { EngineName, MoveClassification } from "./enums";
|
||||
|
||||
export interface MoveEval {
|
||||
export interface PositionEval {
|
||||
bestMove?: string;
|
||||
moveClassification?: MoveClassification;
|
||||
opening?: string;
|
||||
@@ -29,7 +29,7 @@ export interface EngineSettings {
|
||||
}
|
||||
|
||||
export interface GameEval {
|
||||
moves: MoveEval[];
|
||||
positions: PositionEval[];
|
||||
accuracy: Accuracy;
|
||||
settings: EngineSettings;
|
||||
}
|
||||
@@ -38,13 +38,14 @@ export interface EvaluatePositionWithUpdateParams {
|
||||
fen: string;
|
||||
depth?: number;
|
||||
multiPv?: number;
|
||||
setPartialEval: (moveEval: MoveEval) => void;
|
||||
setPartialEval: (positionEval: PositionEval) => void;
|
||||
}
|
||||
|
||||
export type CurrentMove = Partial<Move> & {
|
||||
eval?: MoveEval;
|
||||
lastEval?: MoveEval;
|
||||
};
|
||||
export interface CurrentPosition {
|
||||
lastMove?: Move;
|
||||
eval?: PositionEval;
|
||||
lastEval?: PositionEval;
|
||||
}
|
||||
|
||||
export interface EvaluateGameParams {
|
||||
fens: string[];
|
||||
|
||||