refacto : gameFromUrl
This commit is contained in:
@@ -20,6 +20,7 @@ export const useCurrentMove = () => {
|
||||
return;
|
||||
|
||||
const evalIndex = board.history().length;
|
||||
|
||||
return {
|
||||
...board.history({ verbose: true }).at(-1),
|
||||
eval: gameEval.moves[evalIndex],
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Game } from "@/types/game";
|
||||
import { Chess } from "chess.js";
|
||||
import { openDB, DBSchema, IDBPDatabase } from "idb";
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { useRouter } from "next/router";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
interface GameDatabaseSchema extends DBSchema {
|
||||
@@ -20,6 +21,7 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
|
||||
const [db, setDb] = useState<IDBPDatabase<GameDatabaseSchema> | null>(null);
|
||||
const [games, setGames] = useAtom(gamesAtom);
|
||||
const [fetchGames, setFetchGames] = useAtom(fetchGamesAtom);
|
||||
const [gameFromUrl, setGameFromUrl] = useState<Game | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldFetchGames !== undefined) {
|
||||
@@ -51,6 +53,17 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
|
||||
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) => {
|
||||
if (!db) throw new Error("Database not initialized");
|
||||
|
||||
@@ -89,5 +102,13 @@ export const useGameDatabase = (shouldFetchGames?: boolean) => {
|
||||
|
||||
const isReady = db !== null;
|
||||
|
||||
return { addGame, setGameEval, getGame, deleteGame, games, isReady };
|
||||
return {
|
||||
addGame,
|
||||
setGameEval,
|
||||
getGame,
|
||||
deleteGame,
|
||||
games,
|
||||
isReady,
|
||||
gameFromUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,3 +26,26 @@ export const formatGameToDatabase = (game: Chess): Omit<Game, "id"> => {
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -130,7 +130,23 @@ export class Stockfish {
|
||||
"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 {
|
||||
@@ -151,7 +167,16 @@ export class Stockfish {
|
||||
if (result.startsWith("info")) {
|
||||
const pv = this.getResultPv(result);
|
||||
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 mate = this.getResultProperty(result, "mate");
|
||||
|
||||
@@ -159,6 +184,8 @@ export class Stockfish {
|
||||
pv,
|
||||
cp: cp ? parseInt(cp) : undefined,
|
||||
mate: mate ? parseInt(mate) : undefined,
|
||||
depth: parseInt(depth),
|
||||
multiPv: parseInt(multiPv),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,15 @@ export default function GameDatabase() {
|
||||
headerAlign: "center",
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
field: "eval",
|
||||
headerName: "Evaluation",
|
||||
type: "boolean",
|
||||
headerAlign: "center",
|
||||
align: "center",
|
||||
width: 100,
|
||||
valueGetter: (params) => !!params.row.eval,
|
||||
},
|
||||
{
|
||||
field: "openEvaluation",
|
||||
type: "actions",
|
||||
|
||||
@@ -6,16 +6,13 @@ import { gameAtom, gameEvalAtom } from "./states";
|
||||
import { useAtomValue, useSetAtom } from "jotai";
|
||||
import { getFens } from "@/lib/chess";
|
||||
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export default function AnalyzeButton() {
|
||||
const [engine, setEngine] = useState<Stockfish | null>(null);
|
||||
const [evaluationInProgress, setEvaluationInProgress] = useState(false);
|
||||
const { setGameEval } = useGameDatabase();
|
||||
const { setGameEval, gameFromUrl } = useGameDatabase();
|
||||
const setEval = useSetAtom(gameEvalAtom);
|
||||
const game = useAtomValue(gameAtom);
|
||||
const router = useRouter();
|
||||
const { gameId } = router.query;
|
||||
|
||||
useEffect(() => {
|
||||
const engine = new Stockfish();
|
||||
@@ -43,9 +40,8 @@ export default function AnalyzeButton() {
|
||||
|
||||
setEvaluationInProgress(false);
|
||||
|
||||
if (typeof gameId === "string") {
|
||||
setGameEval(parseInt(gameId), newGameEval);
|
||||
console.log("Game Eval saved to database");
|
||||
if (gameFromUrl) {
|
||||
setGameEval(gameFromUrl.id, newGameEval);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Grid } from "@mui/material";
|
||||
import LoadGameButton from "../loadGame/loadGameButton";
|
||||
import { useRouter } from "next/router";
|
||||
import { useCallback, useEffect } from "react";
|
||||
import { useChessActions } from "@/hooks/useChess";
|
||||
import {
|
||||
@@ -14,12 +13,10 @@ import { useAtomValue, useSetAtom } from "jotai";
|
||||
import { Chess } from "chess.js";
|
||||
|
||||
export default function LoadGame() {
|
||||
const router = useRouter();
|
||||
const { gameId } = router.query;
|
||||
const game = useAtomValue(gameAtom);
|
||||
const gameActions = useChessActions(gameAtom);
|
||||
const boardActions = useChessActions(boardAtom);
|
||||
const { getGame } = useGameDatabase();
|
||||
const { gameFromUrl } = useGameDatabase();
|
||||
const setEval = useSetAtom(gameEvalAtom);
|
||||
const setBoardOrientation = useSetAtom(boardOrientationAtom);
|
||||
|
||||
@@ -35,23 +32,20 @@ export default function LoadGame() {
|
||||
|
||||
useEffect(() => {
|
||||
const loadGame = async () => {
|
||||
if (typeof gameId !== "string") return;
|
||||
|
||||
const gamefromDb = await getGame(parseInt(gameId));
|
||||
if (!gamefromDb) return;
|
||||
if (!gameFromUrl) return;
|
||||
|
||||
const gamefromDbChess = new Chess();
|
||||
gamefromDbChess.loadPgn(gamefromDb.pgn);
|
||||
gamefromDbChess.loadPgn(gameFromUrl.pgn);
|
||||
if (game.history().join() === gamefromDbChess.history().join()) return;
|
||||
|
||||
resetAndSetGamePgn(gamefromDb.pgn);
|
||||
setEval(gamefromDb.eval);
|
||||
resetAndSetGamePgn(gameFromUrl.pgn);
|
||||
setEval(gameFromUrl.eval);
|
||||
};
|
||||
|
||||
loadGame();
|
||||
}, [gameId, getGame, game, resetAndSetGamePgn, setEval]);
|
||||
}, [gameFromUrl, resetAndSetGamePgn, setEval]);
|
||||
|
||||
if (!router.isReady || gameId) return null;
|
||||
if (gameFromUrl) return null;
|
||||
|
||||
return (
|
||||
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
||||
|
||||
@@ -3,22 +3,23 @@ import { Icon } from "@iconify/react";
|
||||
import { IconButton } from "@mui/material";
|
||||
import { useAtomValue } from "jotai";
|
||||
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() {
|
||||
const game = useAtomValue(gameAtom);
|
||||
const board = useAtomValue(boardAtom);
|
||||
const gameEval = useAtomValue(gameEvalAtom);
|
||||
const { addGame, setGameEval } = useGameDatabase();
|
||||
const { addGame, setGameEval, gameFromUrl } = useGameDatabase();
|
||||
|
||||
const router = useRouter();
|
||||
const { gameId } = router.query;
|
||||
|
||||
const isButtonEnabled = router.isReady && typeof gameId === undefined;
|
||||
|
||||
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) {
|
||||
await setGameEval(gameId, gameEval);
|
||||
}
|
||||
@@ -34,7 +35,7 @@ export default function SaveButton() {
|
||||
};
|
||||
|
||||
return (
|
||||
<IconButton onClick={handleSave} disabled={!isButtonEnabled}>
|
||||
<IconButton onClick={handleSave} disabled={!!gameFromUrl}>
|
||||
<Icon icon="ri:save-3-line" />
|
||||
</IconButton>
|
||||
);
|
||||
|
||||
@@ -9,6 +9,8 @@ export interface LineEval {
|
||||
pv: string[];
|
||||
cp?: number;
|
||||
mate?: number;
|
||||
depth: number;
|
||||
multiPv: number;
|
||||
}
|
||||
|
||||
export interface Accuracy {
|
||||
|
||||
Reference in New Issue
Block a user