refacto : gameFromUrl

This commit is contained in:
GuillaumeSD
2024-02-23 23:32:29 +01:00
parent f77a425067
commit 89ca7d8f13
9 changed files with 105 additions and 31 deletions

View File

@@ -20,6 +20,7 @@ export const useCurrentMove = () => {
return; return;
const evalIndex = board.history().length; const evalIndex = board.history().length;
return { return {
...board.history({ verbose: true }).at(-1), ...board.history({ verbose: true }).at(-1),
eval: gameEval.moves[evalIndex], eval: gameEval.moves[evalIndex],

View File

@@ -4,6 +4,7 @@ import { Game } from "@/types/game";
import { Chess } from "chess.js"; import { Chess } from "chess.js";
import { openDB, DBSchema, IDBPDatabase } from "idb"; import { openDB, DBSchema, IDBPDatabase } from "idb";
import { atom, useAtom } from "jotai"; import { atom, useAtom } from "jotai";
import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
interface GameDatabaseSchema extends DBSchema { interface GameDatabaseSchema extends DBSchema {
@@ -20,6 +21,7 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
const [db, setDb] = useState<IDBPDatabase<GameDatabaseSchema> | null>(null); const [db, setDb] = useState<IDBPDatabase<GameDatabaseSchema> | null>(null);
const [games, setGames] = useAtom(gamesAtom); const [games, setGames] = useAtom(gamesAtom);
const [fetchGames, setFetchGames] = useAtom(fetchGamesAtom); const [fetchGames, setFetchGames] = useAtom(fetchGamesAtom);
const [gameFromUrl, setGameFromUrl] = useState<Game | undefined>(undefined);
useEffect(() => { useEffect(() => {
if (shouldFetchGames !== undefined) { if (shouldFetchGames !== undefined) {
@@ -51,6 +53,17 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
loadGames(); loadGames();
}, [loadGames]); }, [loadGames]);
const router = useRouter();
const { gameId } = router.query;
useEffect(() => {
if (typeof gameId === "string") {
getGame(parseInt(gameId)).then((game) => {
setGameFromUrl(game);
});
}
}, [gameId, games]);
const addGame = async (game: Chess) => { const addGame = async (game: Chess) => {
if (!db) throw new Error("Database not initialized"); if (!db) throw new Error("Database not initialized");
@@ -89,5 +102,13 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
const isReady = db !== null; const isReady = db !== null;
return { addGame, setGameEval, getGame, deleteGame, games, isReady }; return {
addGame,
setGameEval,
getGame,
deleteGame,
games,
isReady,
gameFromUrl,
};
}; };

View File

@@ -26,3 +26,26 @@ export const formatGameToDatabase = (game: Chess): Omit<Game, "id"> => {
result: headers.Result, result: headers.Result,
}; };
}; };
export const getGameToSave = (game: Chess, board: Chess): Chess => {
if (game.history().length) return game;
const headers = board.header();
if (!headers.Event) {
board.header("Event", "Freechess Game");
}
if (!headers.Site) {
board.header("Site", "Freechess");
}
if (!headers.Date) {
board.header(
"Date",
new Date().toISOString().split("T")[0].replaceAll("-", ".")
);
}
return board;
};

View File

@@ -130,7 +130,23 @@ export class Stockfish {
"bestmove" "bestmove"
); );
return this.parseResults(results); const parsedResults = this.parseResults(results);
const whiteToPlay = fen.split(" ")[1] === "w";
if (!whiteToPlay) {
const lines = parsedResults.lines.map((line) => ({
...line,
cp: line.cp ? -line.cp : line.cp,
}));
return {
...parsedResults,
lines,
};
}
return parsedResults;
} }
private parseResults(results: string[]): MoveEval { private parseResults(results: string[]): MoveEval {
@@ -151,7 +167,16 @@ export class Stockfish {
if (result.startsWith("info")) { if (result.startsWith("info")) {
const pv = this.getResultPv(result); const pv = this.getResultPv(result);
const multiPv = this.getResultProperty(result, "multipv"); const multiPv = this.getResultProperty(result, "multipv");
if (!pv || !multiPv) continue; const depth = this.getResultProperty(result, "depth");
if (!pv || !multiPv || !depth) continue;
if (
tempResults[multiPv] &&
parseInt(depth) < tempResults[multiPv].depth
) {
continue;
}
const cp = this.getResultProperty(result, "cp"); const cp = this.getResultProperty(result, "cp");
const mate = this.getResultProperty(result, "mate"); const mate = this.getResultProperty(result, "mate");
@@ -159,6 +184,8 @@ export class Stockfish {
pv, pv,
cp: cp ? parseInt(cp) : undefined, cp: cp ? parseInt(cp) : undefined,
mate: mate ? parseInt(mate) : undefined, mate: mate ? parseInt(mate) : undefined,
depth: parseInt(depth),
multiPv: parseInt(multiPv),
}; };
} }
} }

View File

@@ -80,6 +80,15 @@ export default function GameDatabase() {
headerAlign: "center", headerAlign: "center",
align: "center", align: "center",
}, },
{
field: "eval",
headerName: "Evaluation",
type: "boolean",
headerAlign: "center",
align: "center",
width: 100,
valueGetter: (params) => !!params.row.eval,
},
{ {
field: "openEvaluation", field: "openEvaluation",
type: "actions", type: "actions",

View File

@@ -6,16 +6,13 @@ import { gameAtom, gameEvalAtom } from "./states";
import { useAtomValue, useSetAtom } from "jotai"; import { useAtomValue, useSetAtom } from "jotai";
import { getFens } from "@/lib/chess"; import { getFens } from "@/lib/chess";
import { useGameDatabase } from "@/hooks/useGameDatabase"; import { useGameDatabase } from "@/hooks/useGameDatabase";
import { useRouter } from "next/router";
export default function AnalyzeButton() { export default function AnalyzeButton() {
const [engine, setEngine] = useState<Stockfish | null>(null); const [engine, setEngine] = useState<Stockfish | null>(null);
const [evaluationInProgress, setEvaluationInProgress] = useState(false); const [evaluationInProgress, setEvaluationInProgress] = useState(false);
const { setGameEval } = useGameDatabase(); const { setGameEval, gameFromUrl } = useGameDatabase();
const setEval = useSetAtom(gameEvalAtom); const setEval = useSetAtom(gameEvalAtom);
const game = useAtomValue(gameAtom); const game = useAtomValue(gameAtom);
const router = useRouter();
const { gameId } = router.query;
useEffect(() => { useEffect(() => {
const engine = new Stockfish(); const engine = new Stockfish();
@@ -43,9 +40,8 @@ export default function AnalyzeButton() {
setEvaluationInProgress(false); setEvaluationInProgress(false);
if (typeof gameId === "string") { if (gameFromUrl) {
setGameEval(parseInt(gameId), newGameEval); setGameEval(gameFromUrl.id, newGameEval);
console.log("Game Eval saved to database");
} }
}; };

View File

@@ -1,6 +1,5 @@
import { Grid } from "@mui/material"; import { Grid } from "@mui/material";
import LoadGameButton from "../loadGame/loadGameButton"; import LoadGameButton from "../loadGame/loadGameButton";
import { useRouter } from "next/router";
import { useCallback, useEffect } from "react"; import { useCallback, useEffect } from "react";
import { useChessActions } from "@/hooks/useChess"; import { useChessActions } from "@/hooks/useChess";
import { import {
@@ -14,12 +13,10 @@ import { useAtomValue, useSetAtom } from "jotai";
import { Chess } from "chess.js"; import { Chess } from "chess.js";
export default function LoadGame() { export default function LoadGame() {
const router = useRouter();
const { gameId } = router.query;
const game = useAtomValue(gameAtom); const game = useAtomValue(gameAtom);
const gameActions = useChessActions(gameAtom); const gameActions = useChessActions(gameAtom);
const boardActions = useChessActions(boardAtom); const boardActions = useChessActions(boardAtom);
const { getGame } = useGameDatabase(); const { gameFromUrl } = useGameDatabase();
const setEval = useSetAtom(gameEvalAtom); const setEval = useSetAtom(gameEvalAtom);
const setBoardOrientation = useSetAtom(boardOrientationAtom); const setBoardOrientation = useSetAtom(boardOrientationAtom);
@@ -35,23 +32,20 @@ export default function LoadGame() {
useEffect(() => { useEffect(() => {
const loadGame = async () => { const loadGame = async () => {
if (typeof gameId !== "string") return; if (!gameFromUrl) return;
const gamefromDb = await getGame(parseInt(gameId));
if (!gamefromDb) return;
const gamefromDbChess = new Chess(); const gamefromDbChess = new Chess();
gamefromDbChess.loadPgn(gamefromDb.pgn); gamefromDbChess.loadPgn(gameFromUrl.pgn);
if (game.history().join() === gamefromDbChess.history().join()) return; if (game.history().join() === gamefromDbChess.history().join()) return;
resetAndSetGamePgn(gamefromDb.pgn); resetAndSetGamePgn(gameFromUrl.pgn);
setEval(gamefromDb.eval); setEval(gameFromUrl.eval);
}; };
loadGame(); loadGame();
}, [gameId, getGame, game, resetAndSetGamePgn, setEval]); }, [gameFromUrl, resetAndSetGamePgn, setEval]);
if (!router.isReady || gameId) return null; if (gameFromUrl) return null;
return ( return (
<Grid item container xs={12} justifyContent="center" alignItems="center"> <Grid item container xs={12} justifyContent="center" alignItems="center">

View File

@@ -3,22 +3,23 @@ import { Icon } from "@iconify/react";
import { IconButton } from "@mui/material"; import { IconButton } from "@mui/material";
import { useAtomValue } from "jotai"; import { useAtomValue } from "jotai";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { gameAtom, gameEvalAtom } from "../states"; import { boardAtom, gameAtom, gameEvalAtom } from "../states";
import { getGameToSave } from "@/lib/chess";
export default function SaveButton() { export default function SaveButton() {
const game = useAtomValue(gameAtom); const game = useAtomValue(gameAtom);
const board = useAtomValue(boardAtom);
const gameEval = useAtomValue(gameEvalAtom); const gameEval = useAtomValue(gameEvalAtom);
const { addGame, setGameEval } = useGameDatabase(); const { addGame, setGameEval, gameFromUrl } = useGameDatabase();
const router = useRouter(); const router = useRouter();
const { gameId } = router.query;
const isButtonEnabled = router.isReady && typeof gameId === undefined;
const handleSave = async () => { const handleSave = async () => {
if (!isButtonEnabled) return; if (gameFromUrl) return;
const gameId = await addGame(game); const gameToSave = getGameToSave(game, board);
const gameId = await addGame(gameToSave);
if (gameEval) { if (gameEval) {
await setGameEval(gameId, gameEval); await setGameEval(gameId, gameEval);
} }
@@ -34,7 +35,7 @@ export default function SaveButton() {
}; };
return ( return (
<IconButton onClick={handleSave} disabled={!isButtonEnabled}> <IconButton onClick={handleSave} disabled={!!gameFromUrl}>
<Icon icon="ri:save-3-line" /> <Icon icon="ri:save-3-line" />
</IconButton> </IconButton>
); );

View File

@@ -9,6 +9,8 @@ export interface LineEval {
pv: string[]; pv: string[];
cp?: number; cp?: number;
mate?: number; mate?: number;
depth: number;
multiPv: number;
} }
export interface Accuracy { export interface Accuracy {