refacto : gameFromUrl
This commit is contained in:
@@ -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],
|
||||||
|
|||||||
@@ -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,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|||||||
@@ -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),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user