refacto : global refacto

This commit is contained in:
GuillaumeSD
2024-02-22 23:18:02 +01:00
parent 2a74b62bae
commit 2af0959e82
24 changed files with 230 additions and 190 deletions

View File

@@ -0,0 +1,47 @@
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";
export default function AnalyzeButton() {
const [engine, setEngine] = useState<Stockfish | null>(null);
const setEval = useSetAtom(gameEvalAtom);
const game = useAtomValue(gameAtom);
useEffect(() => {
const engine = new Stockfish();
engine.init();
setEngine(engine);
return () => {
engine.shutdown();
};
}, []);
const readyToAnalyse = engine?.isReady() && game.history().length > 0;
const handleAnalyze = async () => {
const gameFens = getFens(game);
if (engine?.isReady() && gameFens.length) {
const newGameEval = await engine.evaluateGame(gameFens);
setEval(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>
);
}

View File

@@ -0,0 +1,30 @@
import { Grid, Typography } from "@mui/material";
import { Chessboard } from "react-chessboard";
import { useAtomValue } from "jotai";
import { boardAtom } from "./states";
export default function Board() {
const board = useAtomValue(boardAtom);
return (
<Grid
item
container
rowGap={2}
justifyContent="center"
alignItems="center"
xs={12}
md={6}
>
<Typography variant="h4" align="center">
White Player (?)
</Typography>
<Chessboard id="BasicBoard" position={board.fen()} />
<Typography variant="h4" align="center">
Black Player (?)
</Typography>
</Grid>
);
}

View File

@@ -0,0 +1,22 @@
import { LineEval } from "@/types/eval";
import { ListItem, ListItemText, Typography } from "@mui/material";
interface Props {
line: LineEval;
}
export default function LineEvaluation({ line }: Props) {
const lineLabel =
line.cp !== undefined
? `${line.cp / 100}`
: line.mate
? `Mate in ${Math.abs(line.mate)}`
: "?";
return (
<ListItem disablePadding>
<ListItemText primary={lineLabel} sx={{ marginRight: 2 }} />
<Typography>{line.pv.slice(0, 7).join(", ")}</Typography>
</ListItem>
);
}

View File

@@ -0,0 +1,42 @@
import { Grid } from "@mui/material";
import LoadGameButton from "../loadGame/loadGameButton";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { useChessActions } from "@/hooks/useChess";
import { boardAtom, gameAtom } from "./states";
import { useGameDatabase } from "@/hooks/useGameDatabase";
export default function LoadGame() {
const router = useRouter();
const { gameId } = router.query;
const gameActions = useChessActions(gameAtom);
const boardActions = useChessActions(boardAtom);
const { getGame } = useGameDatabase();
useEffect(() => {
const loadGame = async () => {
if (typeof gameId !== "string") return;
const game = await getGame(parseInt(gameId));
if (!game) return;
boardActions.reset();
gameActions.setPgn(game.pgn);
};
loadGame();
}, [gameId]);
if (!router.isReady || gameId) return null;
return (
<Grid item container xs={12} justifyContent="center" alignItems="center">
<LoadGameButton
setGame={(game) => {
boardActions.reset();
gameActions.setPgn(game.pgn());
}}
/>
</Grid>
);
}

View File

@@ -0,0 +1,50 @@
import { Icon } from "@iconify/react";
import { Divider, Grid, List, Typography } from "@mui/material";
import { useAtomValue } from "jotai";
import { boardAtom, gameEvalAtom } from "./states";
import LineEvaluation from "./lineEvaluation";
export default function ReviewPanelBody() {
const gameEval = useAtomValue(gameEvalAtom);
if (!gameEval) return null;
const board = useAtomValue(boardAtom);
const evalIndex = board.history().length;
const moveEval = gameEval.moves[evalIndex];
return (
<>
<Divider sx={{ width: "90%", marginY: 3 }} />
<Grid
item
container
xs={12}
justifyContent="center"
alignItems="center"
columnGap={1}
>
<Icon
icon="pepicons-pop:star-filled-circle"
color="#27f019"
height={30}
/>
<Typography variant="h5" align="center">
Game Review
</Typography>
</Grid>
<Typography variant="h6" align="center">
{moveEval ? `${moveEval.bestMove} is the best move` : "Game is over"}
</Typography>
<Grid item container xs={12} justifyContent="center" alignItems="center">
<List>
{moveEval?.lines.map((line) => (
<LineEvaluation key={line.pv[0]} line={line} />
))}
</List>
</Grid>
</>
);
}

View File

@@ -0,0 +1,35 @@
import { Icon } from "@iconify/react";
import { Grid, Typography } from "@mui/material";
import LoadGame from "./loadGame";
import AnalyzeButton from "./analyzeButton";
export default function ReviewPanelHeader() {
return (
<Grid
item
container
justifyContent="center"
alignItems="center"
xs={12}
gap={3}
>
<Grid
item
container
xs={12}
justifyContent="center"
alignItems="center"
columnGap={1}
>
<Icon icon="ph:file-magnifying-glass-fill" height={40} />
<Typography variant="h4" align="center">
Game Report
</Typography>
</Grid>
<LoadGame />
<AnalyzeButton />
</Grid>
);
}

View File

@@ -0,0 +1,51 @@
import { Divider, Grid, IconButton } from "@mui/material";
import { Icon } from "@iconify/react";
import { useAtomValue } from "jotai";
import { boardAtom, gameAtom } from "./states";
import { useChessActions } from "@/hooks/useChess";
export default function ReviewPanelToolBar() {
const game = useAtomValue(gameAtom);
const board = useAtomValue(boardAtom);
const boardActions = useChessActions(boardAtom);
const addNextMoveToGame = () => {
const nextMoveIndex = board.history().length;
const nextMove = game.history({ verbose: true })[nextMoveIndex];
if (nextMove) {
boardActions.move({
from: nextMove.from,
to: nextMove.to,
promotion: nextMove.promotion,
});
}
};
return (
<>
<Divider sx={{ width: "90%", marginY: 3 }} />
<Grid container item justifyContent="center" alignItems="center" xs={12}>
<IconButton>
<Icon icon="eva:flip-fill" />
</IconButton>
<IconButton onClick={() => boardActions.reset()}>
<Icon icon="ri:skip-back-line" />
</IconButton>
<IconButton onClick={() => boardActions.undo()}>
<Icon icon="ri:arrow-left-s-line" height={30} />
</IconButton>
<IconButton onClick={() => addNextMoveToGame()}>
<Icon icon="ri:arrow-right-s-line" height={30} />
</IconButton>
<IconButton>
<Icon icon="ri:skip-forward-line" />
</IconButton>
<IconButton>
<Icon icon="ri:save-3-line" />
</IconButton>
</Grid>
</>
);
}

View File

@@ -0,0 +1,7 @@
import { 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());