feat : set depth & multipv
This commit is contained in:
41
package-lock.json
generated
41
package-lock.json
generated
@@ -12,6 +12,7 @@
|
|||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@fontsource/roboto": "^5.0.3",
|
"@fontsource/roboto": "^5.0.3",
|
||||||
"@iconify/react": "^4.1.0",
|
"@iconify/react": "^4.1.0",
|
||||||
|
"@mui/lab": "^5.0.0-alpha.165",
|
||||||
"@mui/material": "^5.13.4",
|
"@mui/material": "^5.13.4",
|
||||||
"@mui/x-data-grid": "^6.19.4",
|
"@mui/x-data-grid": "^6.19.4",
|
||||||
"chess.js": "^1.0.0-beta.7",
|
"chess.js": "^1.0.0-beta.7",
|
||||||
@@ -569,6 +570,46 @@
|
|||||||
"url": "https://opencollective.com/mui-org"
|
"url": "https://opencollective.com/mui-org"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mui/lab": {
|
||||||
|
"version": "5.0.0-alpha.165",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.165.tgz",
|
||||||
|
"integrity": "sha512-8/zJStT10nh9yrAzLOPTICGhpf5YiGp/JpM0bdTP7u5AE+YT+X2u6QwMxuCrVeW8/WVLAPFg0vtzyfgPcN5T7g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.9",
|
||||||
|
"@mui/base": "5.0.0-beta.36",
|
||||||
|
"@mui/system": "^5.15.9",
|
||||||
|
"@mui/types": "^7.2.13",
|
||||||
|
"@mui/utils": "^5.15.9",
|
||||||
|
"clsx": "^2.1.0",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.5.0",
|
||||||
|
"@emotion/styled": "^11.3.0",
|
||||||
|
"@mui/material": ">=5.15.0",
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^17.0.0 || ^18.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@emotion/styled": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mui/material": {
|
"node_modules/@mui/material": {
|
||||||
"version": "5.15.10",
|
"version": "5.15.10",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.10.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.10.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@fontsource/roboto": "^5.0.3",
|
"@fontsource/roboto": "^5.0.3",
|
||||||
"@iconify/react": "^4.1.0",
|
"@iconify/react": "^4.1.0",
|
||||||
|
"@mui/lab": "^5.0.0-alpha.165",
|
||||||
"@mui/material": "^5.13.4",
|
"@mui/material": "^5.13.4",
|
||||||
"@mui/x-data-grid": "^6.19.4",
|
"@mui/x-data-grid": "^6.19.4",
|
||||||
"chess.js": "^1.0.0-beta.7",
|
"chess.js": "^1.0.0-beta.7",
|
||||||
|
|||||||
45
src/components/slider.tsx
Normal file
45
src/components/slider.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { Grid, Slider as MuiSlider, Typography } from "@mui/material";
|
||||||
|
import { PrimitiveAtom, useAtom } from "jotai";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
atom: PrimitiveAtom<number>;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
label: string;
|
||||||
|
xs?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Slider({ min, max, label, atom, xs }: Props) {
|
||||||
|
const [value, setValue] = useAtom(atom);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
container
|
||||||
|
xs={xs ?? 10}
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
id={`input-${label}`}
|
||||||
|
gutterBottom
|
||||||
|
textAlign="left"
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Typography>
|
||||||
|
<MuiSlider
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
marks={Array.from({ length: max - min + 1 }, (_, i) => ({
|
||||||
|
value: i + min,
|
||||||
|
label: `${i + min}`,
|
||||||
|
}))}
|
||||||
|
valueLabelDisplay="off"
|
||||||
|
value={value}
|
||||||
|
onChange={(_, value) => setValue(value as number)}
|
||||||
|
aria-labelledby={`input-${label}`}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,32 +1,44 @@
|
|||||||
import { boardAtom, gameAtom, gameEvalAtom } from "@/sections/analysis/states";
|
import { boardAtom, gameAtom, gameEvalAtom } from "@/sections/analysis/states";
|
||||||
|
import { MoveEval } from "@/types/eval";
|
||||||
|
import { Move } from "chess.js";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
export type CurrentMove = Partial<Move> & {
|
||||||
|
eval?: MoveEval;
|
||||||
|
lastEval?: MoveEval;
|
||||||
|
};
|
||||||
|
|
||||||
export const useCurrentMove = () => {
|
export const useCurrentMove = () => {
|
||||||
const gameEval = useAtomValue(gameEvalAtom);
|
const gameEval = useAtomValue(gameEvalAtom);
|
||||||
const game = useAtomValue(gameAtom);
|
const game = useAtomValue(gameAtom);
|
||||||
const board = useAtomValue(boardAtom);
|
const board = useAtomValue(boardAtom);
|
||||||
|
|
||||||
const currentEvalMove = useMemo(() => {
|
const currentMove: CurrentMove = useMemo(() => {
|
||||||
if (!gameEval) return undefined;
|
const move = {
|
||||||
|
...board.history({ verbose: true }).at(-1),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!gameEval) return move;
|
||||||
|
|
||||||
const boardHistory = board.history();
|
const boardHistory = board.history();
|
||||||
const gameHistory = game.history();
|
const gameHistory = game.history();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
boardHistory.length >= gameHistory.length ||
|
boardHistory.length <= gameHistory.length &&
|
||||||
gameHistory.slice(0, boardHistory.length).join() !== boardHistory.join()
|
gameHistory.slice(0, boardHistory.length).join() === boardHistory.join()
|
||||||
)
|
) {
|
||||||
return;
|
const evalIndex = board.history().length;
|
||||||
|
|
||||||
const evalIndex = board.history().length;
|
return {
|
||||||
|
...move,
|
||||||
|
eval: gameEval.moves[evalIndex],
|
||||||
|
lastEval: evalIndex > 0 ? gameEval.moves[evalIndex - 1] : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return move;
|
||||||
...board.history({ verbose: true }).at(-1),
|
|
||||||
eval: gameEval.moves[evalIndex],
|
|
||||||
lastEval: evalIndex > 0 ? gameEval.moves[evalIndex - 1] : undefined,
|
|
||||||
};
|
|
||||||
}, [gameEval, board, game]);
|
}, [gameEval, board, game]);
|
||||||
|
|
||||||
return currentEvalMove;
|
return currentMove;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,6 +53,54 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
|
|||||||
loadGames();
|
loadGames();
|
||||||
}, [loadGames]);
|
}, [loadGames]);
|
||||||
|
|
||||||
|
const addGame = useCallback(
|
||||||
|
async (game: Chess) => {
|
||||||
|
if (!db) throw new Error("Database not initialized");
|
||||||
|
|
||||||
|
const gameToAdd = formatGameToDatabase(game);
|
||||||
|
const gameId = await db.add("games", gameToAdd as Game);
|
||||||
|
|
||||||
|
loadGames();
|
||||||
|
|
||||||
|
return gameId;
|
||||||
|
},
|
||||||
|
[db, loadGames]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setGameEval = useCallback(
|
||||||
|
async (gameId: number, evaluation: GameEval) => {
|
||||||
|
if (!db) throw new Error("Database not initialized");
|
||||||
|
|
||||||
|
const game = await db.get("games", gameId);
|
||||||
|
if (!game) throw new Error("Game not found");
|
||||||
|
|
||||||
|
await db.put("games", { ...game, eval: evaluation });
|
||||||
|
|
||||||
|
loadGames();
|
||||||
|
},
|
||||||
|
[db, loadGames]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getGame = useCallback(
|
||||||
|
async (gameId: number) => {
|
||||||
|
if (!db) return undefined;
|
||||||
|
|
||||||
|
return db.get("games", gameId);
|
||||||
|
},
|
||||||
|
[db]
|
||||||
|
);
|
||||||
|
|
||||||
|
const deleteGame = useCallback(
|
||||||
|
async (gameId: number) => {
|
||||||
|
if (!db) throw new Error("Database not initialized");
|
||||||
|
|
||||||
|
await db.delete("games", gameId);
|
||||||
|
|
||||||
|
loadGames();
|
||||||
|
},
|
||||||
|
[db, loadGames]
|
||||||
|
);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { gameId } = router.query;
|
const { gameId } = router.query;
|
||||||
|
|
||||||
@@ -62,43 +110,7 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
|
|||||||
setGameFromUrl(game);
|
setGameFromUrl(game);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [gameId, games]);
|
}, [gameId, setGameFromUrl, getGame]);
|
||||||
|
|
||||||
const addGame = async (game: Chess) => {
|
|
||||||
if (!db) throw new Error("Database not initialized");
|
|
||||||
|
|
||||||
const gameToAdd = formatGameToDatabase(game);
|
|
||||||
const gameId = await db.add("games", gameToAdd as Game);
|
|
||||||
|
|
||||||
loadGames();
|
|
||||||
|
|
||||||
return gameId;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setGameEval = async (gameId: number, evaluation: GameEval) => {
|
|
||||||
if (!db) throw new Error("Database not initialized");
|
|
||||||
|
|
||||||
const game = await db.get("games", gameId);
|
|
||||||
if (!game) throw new Error("Game not found");
|
|
||||||
|
|
||||||
await db.put("games", { ...game, eval: evaluation });
|
|
||||||
|
|
||||||
loadGames();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getGame = async (gameId: number) => {
|
|
||||||
if (!db) return undefined;
|
|
||||||
|
|
||||||
return db.get("games", gameId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteGame = async (gameId: number) => {
|
|
||||||
if (!db) throw new Error("Database not initialized");
|
|
||||||
|
|
||||||
await db.delete("games", gameId);
|
|
||||||
|
|
||||||
loadGames();
|
|
||||||
};
|
|
||||||
|
|
||||||
const isReady = db !== null;
|
const isReady = db !== null;
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ export default function GameReport() {
|
|||||||
item
|
item
|
||||||
container
|
container
|
||||||
rowGap={2}
|
rowGap={2}
|
||||||
paddingLeft={{ xs: 0, md: 6 }}
|
paddingLeft={{ xs: 0, lg: 6 }}
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
xs={12}
|
xs={12}
|
||||||
md={6}
|
lg={6}
|
||||||
>
|
>
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import { Stockfish } from "@/lib/engine/stockfish";
|
|
||||||
import { Icon } from "@iconify/react";
|
|
||||||
import { Button, Grid } from "@mui/material";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { gameAtom, gameEvalAtom } from "./states";
|
|
||||||
import { useAtomValue, useSetAtom } from "jotai";
|
|
||||||
import { getFens } from "@/lib/chess";
|
|
||||||
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
|
||||||
|
|
||||||
export default function AnalyzeButton() {
|
|
||||||
const [engine, setEngine] = useState<Stockfish | null>(null);
|
|
||||||
const [evaluationInProgress, setEvaluationInProgress] = useState(false);
|
|
||||||
const { setGameEval, gameFromUrl } = useGameDatabase();
|
|
||||||
const setEval = useSetAtom(gameEvalAtom);
|
|
||||||
const game = useAtomValue(gameAtom);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const engine = new Stockfish();
|
|
||||||
engine.init().then(() => {
|
|
||||||
setEngine(engine);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
engine.shutdown();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const readyToAnalyse =
|
|
||||||
engine?.isReady() && game.history().length > 0 && !evaluationInProgress;
|
|
||||||
|
|
||||||
const handleAnalyze = async () => {
|
|
||||||
const gameFens = getFens(game);
|
|
||||||
if (!engine?.isReady() || gameFens.length === 0 || evaluationInProgress)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setEvaluationInProgress(true);
|
|
||||||
|
|
||||||
const newGameEval = await engine.evaluateGame(gameFens);
|
|
||||||
setEval(newGameEval);
|
|
||||||
|
|
||||||
setEvaluationInProgress(false);
|
|
||||||
|
|
||||||
if (gameFromUrl) {
|
|
||||||
setGameEval(gameFromUrl.id, newGameEval);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
size="large"
|
|
||||||
startIcon={<Icon icon="streamline:magnifying-glass-solid" />}
|
|
||||||
onClick={handleAnalyze}
|
|
||||||
disabled={!readyToAnalyse}
|
|
||||||
>
|
|
||||||
Analyse
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -6,26 +6,16 @@ import LineEvaluation from "./lineEvaluation";
|
|||||||
import { useCurrentMove } from "@/hooks/useCurrentMove";
|
import { useCurrentMove } from "@/hooks/useCurrentMove";
|
||||||
|
|
||||||
export default function ReviewPanelBody() {
|
export default function ReviewPanelBody() {
|
||||||
|
const move = useCurrentMove();
|
||||||
const game = useAtomValue(gameAtom);
|
const game = useAtomValue(gameAtom);
|
||||||
const board = useAtomValue(boardAtom);
|
const board = useAtomValue(boardAtom);
|
||||||
|
|
||||||
const move = useCurrentMove();
|
const boardHistory = board.history();
|
||||||
|
const gameHistory = game.history();
|
||||||
|
|
||||||
const getBestMoveLabel = () => {
|
const bestMove = move?.lastEval?.bestMove;
|
||||||
const bestMove = move?.lastEval?.bestMove;
|
const isGameOver =
|
||||||
if (bestMove) {
|
gameHistory.length > 0 && boardHistory.join() === gameHistory.join();
|
||||||
return `${bestMove} was the best move`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const boardHistory = board.history();
|
|
||||||
const gameHistory = game.history();
|
|
||||||
|
|
||||||
if (game.isGameOver() && boardHistory.join() === gameHistory.join()) {
|
|
||||||
return "Game is over";
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -49,9 +39,21 @@ export default function ReviewPanelBody() {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Typography variant="h6" align="center">
|
{!!bestMove && (
|
||||||
{getBestMoveLabel()}
|
<Grid item xs={12}>
|
||||||
</Typography>
|
<Typography variant="h6" align="center">
|
||||||
|
{`${bestMove} was the best move`}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isGameOver && (
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Typography variant="h6" align="center">
|
||||||
|
Game is over
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
|
||||||
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
||||||
<List>
|
<List>
|
||||||
|
|||||||
111
src/sections/analysis/reviewPanelHeader/analyzePanel.tsx
Normal file
111
src/sections/analysis/reviewPanelHeader/analyzePanel.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { Stockfish } from "@/lib/engine/stockfish";
|
||||||
|
import { Icon } from "@iconify/react";
|
||||||
|
import { Grid } from "@mui/material";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
engineDepthAtom,
|
||||||
|
engineMultiPvAtom,
|
||||||
|
gameAtom,
|
||||||
|
gameEvalAtom,
|
||||||
|
} from "../states";
|
||||||
|
import { useAtomValue, useSetAtom } from "jotai";
|
||||||
|
import { getFens } from "@/lib/chess";
|
||||||
|
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
||||||
|
import { LoadingButton } from "@mui/lab";
|
||||||
|
import Slider from "@/components/slider";
|
||||||
|
|
||||||
|
export default function AnalyzePanel() {
|
||||||
|
const [engine, setEngine] = useState<Stockfish | null>(null);
|
||||||
|
const [evaluationInProgress, setEvaluationInProgress] = useState(false);
|
||||||
|
const engineDepth = useAtomValue(engineDepthAtom);
|
||||||
|
const engineMultiPv = useAtomValue(engineMultiPvAtom);
|
||||||
|
const { setGameEval, gameFromUrl } = useGameDatabase();
|
||||||
|
const setEval = useSetAtom(gameEvalAtom);
|
||||||
|
const game = useAtomValue(gameAtom);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const engine = new Stockfish();
|
||||||
|
engine.init().then(() => {
|
||||||
|
setEngine(engine);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
engine.shutdown();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const readyToAnalyse =
|
||||||
|
engine?.isReady() && game.history().length > 0 && !evaluationInProgress;
|
||||||
|
|
||||||
|
const handleAnalyze = async () => {
|
||||||
|
const gameFens = getFens(game);
|
||||||
|
if (!engine?.isReady() || gameFens.length === 0 || evaluationInProgress)
|
||||||
|
return;
|
||||||
|
|
||||||
|
setEvaluationInProgress(true);
|
||||||
|
|
||||||
|
const newGameEval = await engine.evaluateGame(
|
||||||
|
gameFens,
|
||||||
|
engineDepth,
|
||||||
|
engineMultiPv
|
||||||
|
);
|
||||||
|
setEval(newGameEval);
|
||||||
|
|
||||||
|
setEvaluationInProgress(false);
|
||||||
|
|
||||||
|
if (gameFromUrl) {
|
||||||
|
setGameEval(gameFromUrl.id, newGameEval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
container
|
||||||
|
xs={12}
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
rowGap={4}
|
||||||
|
>
|
||||||
|
<Slider label="Maximum depth" atom={engineDepthAtom} min={10} max={30} />
|
||||||
|
|
||||||
|
<Slider
|
||||||
|
label="Number of lines"
|
||||||
|
atom={engineMultiPvAtom}
|
||||||
|
min={1}
|
||||||
|
max={6}
|
||||||
|
xs={6}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
container
|
||||||
|
xs={12}
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
marginTop={1}
|
||||||
|
>
|
||||||
|
<LoadingButton
|
||||||
|
variant="contained"
|
||||||
|
size="large"
|
||||||
|
startIcon={
|
||||||
|
!evaluationInProgress && (
|
||||||
|
<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"}
|
||||||
|
</LoadingButton>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { Grid, Typography } from "@mui/material";
|
import { Grid, Typography } from "@mui/material";
|
||||||
import LoadGame from "./loadGame";
|
import LoadGame from "./loadGame";
|
||||||
import AnalyzeButton from "./analyzeButton";
|
import AnalyzePanel from "./analyzePanel";
|
||||||
|
|
||||||
export default function ReviewPanelHeader() {
|
export default function ReviewPanelHeader() {
|
||||||
return (
|
return (
|
||||||
@@ -29,7 +29,7 @@ export default function ReviewPanelHeader() {
|
|||||||
|
|
||||||
<LoadGame />
|
<LoadGame />
|
||||||
|
|
||||||
<AnalyzeButton />
|
<AnalyzePanel />
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Grid } from "@mui/material";
|
import { Grid } from "@mui/material";
|
||||||
import LoadGameButton from "../loadGame/loadGameButton";
|
import LoadGameButton from "../../loadGame/loadGameButton";
|
||||||
import { useCallback, useEffect } from "react";
|
import { useCallback, useEffect } from "react";
|
||||||
import { useChessActions } from "@/hooks/useChess";
|
import { useChessActions } from "@/hooks/useChess";
|
||||||
import {
|
import {
|
||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
boardOrientationAtom,
|
boardOrientationAtom,
|
||||||
gameAtom,
|
gameAtom,
|
||||||
gameEvalAtom,
|
gameEvalAtom,
|
||||||
} from "./states";
|
} from "../states";
|
||||||
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
||||||
import { useAtomValue, useSetAtom } from "jotai";
|
import { useAtomValue, useSetAtom } from "jotai";
|
||||||
import { Chess } from "chess.js";
|
import { Chess } from "chess.js";
|
||||||
@@ -43,7 +43,7 @@ export default function LoadGame() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
loadGame();
|
loadGame();
|
||||||
}, [gameFromUrl, resetAndSetGamePgn, setEval]);
|
}, [gameFromUrl, game, resetAndSetGamePgn, setEval]);
|
||||||
|
|
||||||
if (gameFromUrl) return null;
|
if (gameFromUrl) return null;
|
||||||
|
|
||||||
@@ -11,11 +11,13 @@ export default function SaveButton() {
|
|||||||
const board = useAtomValue(boardAtom);
|
const board = useAtomValue(boardAtom);
|
||||||
const gameEval = useAtomValue(gameEvalAtom);
|
const gameEval = useAtomValue(gameEvalAtom);
|
||||||
const { addGame, setGameEval, gameFromUrl } = useGameDatabase();
|
const { addGame, setGameEval, gameFromUrl } = useGameDatabase();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const enableSave =
|
||||||
|
!gameFromUrl && (board.history().length || game.history().length);
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
if (gameFromUrl) return;
|
if (!enableSave) return;
|
||||||
|
|
||||||
const gameToSave = getGameToSave(game, board);
|
const gameToSave = getGameToSave(game, board);
|
||||||
|
|
||||||
@@ -35,8 +37,16 @@ export default function SaveButton() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton onClick={handleSave} disabled={!!gameFromUrl}>
|
<>
|
||||||
<Icon icon="ri:save-3-line" />
|
{gameFromUrl ? (
|
||||||
</IconButton>
|
<IconButton disabled={true}>
|
||||||
|
<Icon icon="ri:folder-check-line" />
|
||||||
|
</IconButton>
|
||||||
|
) : (
|
||||||
|
<IconButton onClick={handleSave} disabled={!enableSave}>
|
||||||
|
<Icon icon="ri:save-3-line" />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,3 +6,6 @@ export const gameEvalAtom = atom<GameEval | undefined>(undefined);
|
|||||||
export const gameAtom = atom(new Chess());
|
export const gameAtom = atom(new Chess());
|
||||||
export const boardAtom = atom(new Chess());
|
export const boardAtom = atom(new Chess());
|
||||||
export const boardOrientationAtom = atom(true);
|
export const boardOrientationAtom = atom(true);
|
||||||
|
|
||||||
|
export const engineDepthAtom = atom(16);
|
||||||
|
export const engineMultiPvAtom = atom(3);
|
||||||
|
|||||||
Reference in New Issue
Block a user