feat : add arrow opt out options
This commit is contained in:
@@ -1,15 +1,18 @@
|
|||||||
import { Stockfish16 } from "@/lib/engine/stockfish16";
|
import { Stockfish16 } from "@/lib/engine/stockfish16";
|
||||||
import { UciEngine } from "@/lib/engine/uciEngine";
|
import { UciEngine } from "@/lib/engine/uciEngine";
|
||||||
|
import { engineMultiPvAtom } from "@/sections/analysis/states";
|
||||||
import { EngineName } from "@/types/enums";
|
import { EngineName } from "@/types/enums";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
export const useEngine = (engineName: EngineName) => {
|
export const useEngine = (engineName: EngineName) => {
|
||||||
const [engine, setEngine] = useState<UciEngine | null>(null);
|
const [engine, setEngine] = useState<UciEngine | null>(null);
|
||||||
|
const multiPv = useAtomValue(engineMultiPvAtom);
|
||||||
|
|
||||||
const pickEngine = (engine: EngineName): UciEngine => {
|
const pickEngine = (engine: EngineName): UciEngine => {
|
||||||
switch (engine) {
|
switch (engine) {
|
||||||
case EngineName.Stockfish16:
|
case EngineName.Stockfish16:
|
||||||
return new Stockfish16();
|
return new Stockfish16(multiPv);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { EngineName } from "@/types/enums";
|
|||||||
import { UciEngine } from "./uciEngine";
|
import { UciEngine } from "./uciEngine";
|
||||||
|
|
||||||
export class Stockfish16 extends UciEngine {
|
export class Stockfish16 extends UciEngine {
|
||||||
constructor() {
|
constructor(multiPv: number) {
|
||||||
const isWasmSupported = Stockfish16.isWasmSupported();
|
const isWasmSupported = Stockfish16.isWasmSupported();
|
||||||
|
|
||||||
const enginePath = isWasmSupported
|
const enginePath = isWasmSupported
|
||||||
? "engines/stockfish-wasm/stockfish-nnue-16-single.js"
|
? "engines/stockfish-wasm/stockfish-nnue-16-single.js"
|
||||||
: "engines/stockfish.js";
|
: "engines/stockfish.js";
|
||||||
|
|
||||||
super(EngineName.Stockfish16, enginePath);
|
super(EngineName.Stockfish16, enginePath, multiPv);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static isWasmSupported() {
|
public static isWasmSupported() {
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ export abstract class UciEngine {
|
|||||||
private worker: Worker;
|
private worker: Worker;
|
||||||
private ready = false;
|
private ready = false;
|
||||||
private engineName: EngineName;
|
private engineName: EngineName;
|
||||||
private multiPv = 3;
|
private multiPv: number;
|
||||||
|
|
||||||
constructor(engineName: EngineName, enginePath: string) {
|
constructor(engineName: EngineName, enginePath: string, multiPv: number) {
|
||||||
this.engineName = engineName;
|
this.engineName = engineName;
|
||||||
|
this.multiPv = multiPv;
|
||||||
|
|
||||||
this.worker = new Worker(enginePath);
|
this.worker = new Worker(enginePath);
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ export abstract class UciEngine {
|
|||||||
|
|
||||||
public async init(): Promise<void> {
|
public async init(): Promise<void> {
|
||||||
await this.sendCommands(["uci"], "uciok");
|
await this.sendCommands(["uci"], "uciok");
|
||||||
await this.setMultiPv(3, false);
|
await this.setMultiPv(this.multiPv, false);
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
console.log(`${this.engineName} initialized`);
|
console.log(`${this.engineName} initialized`);
|
||||||
}
|
}
|
||||||
@@ -81,24 +82,21 @@ export abstract class UciEngine {
|
|||||||
public async evaluateGame(
|
public async evaluateGame(
|
||||||
fens: string[],
|
fens: string[],
|
||||||
depth = 16,
|
depth = 16,
|
||||||
multiPv = 3
|
multiPv = this.multiPv
|
||||||
): Promise<GameEval> {
|
): Promise<GameEval> {
|
||||||
this.throwErrorIfNotReady();
|
this.throwErrorIfNotReady();
|
||||||
this.ready = false;
|
this.ready = false;
|
||||||
|
|
||||||
await this.setMultiPv(multiPv, false);
|
|
||||||
await this.sendCommands(["ucinewgame", "isready"], "readyok");
|
await this.sendCommands(["ucinewgame", "isready"], "readyok");
|
||||||
this.worker.postMessage("position startpos");
|
this.worker.postMessage("position startpos");
|
||||||
|
|
||||||
const moves: MoveEval[] = [];
|
const moves: MoveEval[] = [];
|
||||||
for (const fen of fens) {
|
for (const fen of fens) {
|
||||||
console.log(`Evaluating position: ${fen}`);
|
const result = await this.evaluatePosition(fen, depth, multiPv, false);
|
||||||
const result = await this.evaluatePosition(fen, depth, false);
|
|
||||||
moves.push(result);
|
moves.push(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
console.log(moves);
|
|
||||||
return {
|
return {
|
||||||
moves,
|
moves,
|
||||||
accuracy: { white: 82.34, black: 67.49 }, // TODO: Calculate accuracy
|
accuracy: { white: 82.34, black: 67.49 }, // TODO: Calculate accuracy
|
||||||
@@ -114,12 +112,16 @@ export abstract class UciEngine {
|
|||||||
public async evaluatePosition(
|
public async evaluatePosition(
|
||||||
fen: string,
|
fen: string,
|
||||||
depth = 16,
|
depth = 16,
|
||||||
|
multiPv = this.multiPv,
|
||||||
checkIsReady = true
|
checkIsReady = true
|
||||||
): Promise<MoveEval> {
|
): Promise<MoveEval> {
|
||||||
if (checkIsReady) {
|
if (checkIsReady) {
|
||||||
this.throwErrorIfNotReady();
|
this.throwErrorIfNotReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.setMultiPv(multiPv, checkIsReady);
|
||||||
|
|
||||||
|
console.log(`Evaluating position: ${fen}`);
|
||||||
const results = await this.sendCommands(
|
const results = await this.sendCommands(
|
||||||
[`position fen ${fen}`, `go depth ${depth}`],
|
[`position fen ${fen}`, `go depth ${depth}`],
|
||||||
"bestmove"
|
"bestmove"
|
||||||
|
|||||||
@@ -60,11 +60,15 @@ export default function GameDatabase() {
|
|||||||
width: 150,
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "white",
|
field: "whiteLabel",
|
||||||
headerName: "White",
|
headerName: "White",
|
||||||
width: 150,
|
width: 200,
|
||||||
headerAlign: "center",
|
headerAlign: "center",
|
||||||
align: "center",
|
align: "center",
|
||||||
|
valueGetter: (params) =>
|
||||||
|
`${params.row.white.name ?? "Unknown"} (${
|
||||||
|
params.row.white.rating ?? "?"
|
||||||
|
})`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "result",
|
field: "result",
|
||||||
@@ -74,11 +78,15 @@ export default function GameDatabase() {
|
|||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "black",
|
field: "blackLabel",
|
||||||
headerName: "Black",
|
headerName: "Black",
|
||||||
width: 150,
|
width: 200,
|
||||||
headerAlign: "center",
|
headerAlign: "center",
|
||||||
align: "center",
|
align: "center",
|
||||||
|
valueGetter: (params) =>
|
||||||
|
`${params.row.black.name ?? "Unknown"} (${
|
||||||
|
params.row.black.rating ?? "?"
|
||||||
|
})`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "eval",
|
field: "eval",
|
||||||
@@ -136,15 +144,14 @@ export default function GameDatabase() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container rowSpacing={3} justifyContent="center" alignItems="center">
|
<Grid
|
||||||
<Grid
|
container
|
||||||
item
|
justifyContent="center"
|
||||||
container
|
alignItems="center"
|
||||||
xs={12}
|
gap={4}
|
||||||
justifyContent="center"
|
marginTop={6}
|
||||||
alignItems="center"
|
>
|
||||||
spacing={4}
|
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
||||||
>
|
|
||||||
<Grid item container justifyContent="center" sx={{ maxWidth: "250px" }}>
|
<Grid item container justifyContent="center" sx={{ maxWidth: "250px" }}>
|
||||||
<LoadGameButton />
|
<LoadGameButton />
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -152,7 +159,7 @@ export default function GameDatabase() {
|
|||||||
|
|
||||||
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
||||||
<Typography variant="subtitle2">
|
<Typography variant="subtitle2">
|
||||||
You have {0} games in your database
|
You have {games.length} games in your database
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,37 @@
|
|||||||
|
import { useChessActions } from "@/hooks/useChess";
|
||||||
import Board from "@/sections/analysis/board";
|
import Board from "@/sections/analysis/board";
|
||||||
import ReviewPanelBody from "@/sections/analysis/reviewPanelBody";
|
import ReviewPanelBody from "@/sections/analysis/reviewPanelBody";
|
||||||
import ReviewPanelHeader from "@/sections/analysis/reviewPanelHeader";
|
import ReviewPanelHeader from "@/sections/analysis/reviewPanelHeader";
|
||||||
import ReviewPanelToolBar from "@/sections/analysis/reviewPanelToolbar";
|
import ReviewPanelToolBar from "@/sections/analysis/reviewPanelToolbar";
|
||||||
|
import {
|
||||||
|
boardAtom,
|
||||||
|
boardOrientationAtom,
|
||||||
|
gameAtom,
|
||||||
|
gameEvalAtom,
|
||||||
|
} from "@/sections/analysis/states";
|
||||||
import { Grid } from "@mui/material";
|
import { Grid } from "@mui/material";
|
||||||
|
import { Chess } from "chess.js";
|
||||||
|
import { useSetAtom } from "jotai";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export default function GameReport() {
|
export default function GameReport() {
|
||||||
|
const boardActions = useChessActions(boardAtom);
|
||||||
|
const gameActions = useChessActions(gameAtom);
|
||||||
|
const setEval = useSetAtom(gameEvalAtom);
|
||||||
|
const setBoardOrientation = useSetAtom(boardOrientationAtom);
|
||||||
|
const router = useRouter();
|
||||||
|
const { gameId } = router.query;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!gameId) {
|
||||||
|
boardActions.reset();
|
||||||
|
setEval(undefined);
|
||||||
|
setBoardOrientation(true);
|
||||||
|
gameActions.setPgn(new Chess().pgn());
|
||||||
|
}
|
||||||
|
}, [gameId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { Grid } from "@mui/material";
|
import { Grid } from "@mui/material";
|
||||||
import { Chessboard } from "react-chessboard";
|
import { Chessboard } from "react-chessboard";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { boardAtom, boardOrientationAtom } from "../states";
|
import {
|
||||||
|
boardAtom,
|
||||||
|
boardOrientationAtom,
|
||||||
|
showBestMoveArrowAtom,
|
||||||
|
showPlayerMoveArrowAtom,
|
||||||
|
} from "../states";
|
||||||
import { Arrow, Square } from "react-chessboard/dist/chessboard/types";
|
import { Arrow, Square } from "react-chessboard/dist/chessboard/types";
|
||||||
import { useChessActions } from "@/hooks/useChess";
|
import { useChessActions } from "@/hooks/useChess";
|
||||||
import { useCurrentMove } from "@/hooks/useCurrentMove";
|
import { useCurrentMove } from "@/hooks/useCurrentMove";
|
||||||
@@ -11,6 +16,8 @@ import PlayerInfo from "./playerInfo";
|
|||||||
export default function Board() {
|
export default function Board() {
|
||||||
const board = useAtomValue(boardAtom);
|
const board = useAtomValue(boardAtom);
|
||||||
const boardOrientation = useAtomValue(boardOrientationAtom);
|
const boardOrientation = useAtomValue(boardOrientationAtom);
|
||||||
|
const showBestMoveArrow = useAtomValue(showBestMoveArrowAtom);
|
||||||
|
const showPlayerMoveArrow = useAtomValue(showPlayerMoveArrowAtom);
|
||||||
const boardActions = useChessActions(boardAtom);
|
const boardActions = useChessActions(boardAtom);
|
||||||
const currentMove = useCurrentMove();
|
const currentMove = useCurrentMove();
|
||||||
|
|
||||||
@@ -29,25 +36,37 @@ export default function Board() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const customArrows: Arrow[] = useMemo(() => {
|
const customArrows: Arrow[] = useMemo(() => {
|
||||||
if (!currentMove?.lastEval) return [];
|
const arrows: Arrow[] = [];
|
||||||
|
|
||||||
const bestMoveArrow = [
|
if (currentMove?.lastEval && showBestMoveArrow) {
|
||||||
currentMove.lastEval.bestMove.slice(0, 2),
|
const bestMoveArrow = [
|
||||||
currentMove.lastEval.bestMove.slice(2, 4),
|
currentMove.lastEval.bestMove.slice(0, 2),
|
||||||
"#3aab18",
|
currentMove.lastEval.bestMove.slice(2, 4),
|
||||||
] as Arrow;
|
"#3aab18",
|
||||||
|
] as Arrow;
|
||||||
|
|
||||||
if (
|
arrows.push(bestMoveArrow);
|
||||||
!currentMove.from ||
|
|
||||||
!currentMove.to ||
|
|
||||||
(currentMove.from === bestMoveArrow[0] &&
|
|
||||||
currentMove.to === bestMoveArrow[1])
|
|
||||||
) {
|
|
||||||
return [bestMoveArrow];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [[currentMove.from, currentMove.to, "#ffaa00"], bestMoveArrow];
|
if (currentMove.from && currentMove.to && showPlayerMoveArrow) {
|
||||||
}, [currentMove]);
|
const playerMoveArrow: Arrow = [
|
||||||
|
currentMove.from,
|
||||||
|
currentMove.to,
|
||||||
|
"#ffaa00",
|
||||||
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
arrows.every(
|
||||||
|
(arrow) =>
|
||||||
|
arrow[0] !== playerMoveArrow[0] || arrow[1] !== playerMoveArrow[1]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
arrows.push(playerMoveArrow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arrows;
|
||||||
|
}, [currentMove, showBestMoveArrow, showPlayerMoveArrow]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
@@ -69,7 +88,7 @@ export default function Board() {
|
|||||||
maxWidth={"80vh"}
|
maxWidth={"80vh"}
|
||||||
>
|
>
|
||||||
<Chessboard
|
<Chessboard
|
||||||
id="BasicBoard"
|
id="AnalysisBoard"
|
||||||
position={board.fen()}
|
position={board.fen()}
|
||||||
onPieceDrop={onPieceDrop}
|
onPieceDrop={onPieceDrop}
|
||||||
boardOrientation={boardOrientation ? "white" : "black"}
|
boardOrientation={boardOrientation ? "white" : "black"}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export default function AnalyzePanel() {
|
|||||||
engineDepth,
|
engineDepth,
|
||||||
engineMultiPv
|
engineMultiPv
|
||||||
);
|
);
|
||||||
|
console.log(newGameEval);
|
||||||
setEval(newGameEval);
|
setEval(newGameEval);
|
||||||
|
|
||||||
setEvaluationInProgress(false);
|
setEvaluationInProgress(false);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Grid, Typography } from "@mui/material";
|
import { Grid, Typography } from "@mui/material";
|
||||||
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { gameAtom } from "../states";
|
import { gameAtom } from "../../states";
|
||||||
import PlayerInfo from "./playerInfo";
|
import PlayerInfo from "./playerInfo";
|
||||||
|
|
||||||
export default function GamePanel() {
|
export default function GamePanel() {
|
||||||
@@ -12,7 +12,14 @@ export default function GamePanel() {
|
|||||||
|
|
||||||
if (!hasGameInfo) {
|
if (!hasGameInfo) {
|
||||||
return (
|
return (
|
||||||
<Grid item container xs={12} justifyContent="center" alignItems="center">
|
<Grid
|
||||||
|
item
|
||||||
|
container
|
||||||
|
xs={12}
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
marginY={1}
|
||||||
|
>
|
||||||
<Typography variant="h6">No game loaded</Typography>
|
<Typography variant="h6">No game loaded</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
||||||
import { Grid, Typography } from "@mui/material";
|
import { Grid, Typography } from "@mui/material";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { gameAtom } from "../states";
|
import { gameAtom } from "../../states";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
color: "white" | "black";
|
color: "white" | "black";
|
||||||
@@ -54,7 +54,7 @@ export default function LoadGame() {
|
|||||||
<LoadGameButton
|
<LoadGameButton
|
||||||
label={isGameLoaded ? "Load another game" : "Load game"}
|
label={isGameLoaded ? "Load another game" : "Load game"}
|
||||||
setGame={async (game) => {
|
setGame={async (game) => {
|
||||||
await router.push("");
|
await router.push("/");
|
||||||
resetAndSetGamePgn(game.pgn());
|
resetAndSetGamePgn(game.pgn());
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
import { boardOrientationAtom } from "../states";
|
import { boardOrientationAtom } from "../states";
|
||||||
import { IconButton } from "@mui/material";
|
import { IconButton, Tooltip } from "@mui/material";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
|
|
||||||
export default function FlipBoardButton() {
|
export default function FlipBoardButton() {
|
||||||
const setBoardOrientation = useSetAtom(boardOrientationAtom);
|
const setBoardOrientation = useSetAtom(boardOrientationAtom);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton onClick={() => setBoardOrientation((prev) => !prev)}>
|
<Tooltip title="Flip board">
|
||||||
<Icon icon="eva:flip-fill" />
|
<IconButton onClick={() => setBoardOrientation((prev) => !prev)}>
|
||||||
</IconButton>
|
<Icon icon="eva:flip-fill" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { IconButton } from "@mui/material";
|
import { Grid, IconButton, Tooltip } from "@mui/material";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { boardAtom, gameAtom } from "../states";
|
import { boardAtom, gameAtom } from "../states";
|
||||||
import { useChessActions } from "@/hooks/useChess";
|
import { useChessActions } from "@/hooks/useChess";
|
||||||
@@ -15,14 +15,18 @@ export default function GoToLastPositionButton() {
|
|||||||
const isButtonDisabled = boardHistory >= gameHistory;
|
const isButtonDisabled = boardHistory >= gameHistory;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<Tooltip title="Go to final position">
|
||||||
onClick={() => {
|
<Grid>
|
||||||
if (isButtonDisabled) return;
|
<IconButton
|
||||||
boardActions.setPgn(game.pgn());
|
onClick={() => {
|
||||||
}}
|
if (isButtonDisabled) return;
|
||||||
disabled={isButtonDisabled}
|
boardActions.setPgn(game.pgn());
|
||||||
>
|
}}
|
||||||
<Icon icon="ri:skip-forward-line" />
|
disabled={isButtonDisabled}
|
||||||
</IconButton>
|
>
|
||||||
|
<Icon icon="ri:skip-forward-line" />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
import { Divider, Grid, IconButton } from "@mui/material";
|
import {
|
||||||
|
Checkbox,
|
||||||
|
Divider,
|
||||||
|
FormControlLabel,
|
||||||
|
Grid,
|
||||||
|
IconButton,
|
||||||
|
Tooltip,
|
||||||
|
} from "@mui/material";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { boardAtom } from "../states";
|
import {
|
||||||
|
boardAtom,
|
||||||
|
showBestMoveArrowAtom,
|
||||||
|
showPlayerMoveArrowAtom,
|
||||||
|
} from "../states";
|
||||||
import { useChessActions } from "@/hooks/useChess";
|
import { useChessActions } from "@/hooks/useChess";
|
||||||
import FlipBoardButton from "./flipBoardButton";
|
import FlipBoardButton from "./flipBoardButton";
|
||||||
import NextMoveButton from "./nextMoveButton";
|
import NextMoveButton from "./nextMoveButton";
|
||||||
@@ -9,6 +20,8 @@ import GoToLastPositionButton from "./goToLastPositionButton";
|
|||||||
import SaveButton from "./saveButton";
|
import SaveButton from "./saveButton";
|
||||||
|
|
||||||
export default function ReviewPanelToolBar() {
|
export default function ReviewPanelToolBar() {
|
||||||
|
const [showBestMove, setShowBestMove] = useAtom(showBestMoveArrowAtom);
|
||||||
|
const [showPlayerMove, setShowPlayerMove] = useAtom(showPlayerMoveArrowAtom);
|
||||||
const board = useAtomValue(boardAtom);
|
const board = useAtomValue(boardAtom);
|
||||||
const boardActions = useChessActions(boardAtom);
|
const boardActions = useChessActions(boardAtom);
|
||||||
|
|
||||||
@@ -21,19 +34,27 @@ export default function ReviewPanelToolBar() {
|
|||||||
<Grid container item justifyContent="center" alignItems="center" xs={12}>
|
<Grid container item justifyContent="center" alignItems="center" xs={12}>
|
||||||
<FlipBoardButton />
|
<FlipBoardButton />
|
||||||
|
|
||||||
<IconButton
|
<Tooltip title="Reset board">
|
||||||
onClick={() => boardActions.reset()}
|
<Grid>
|
||||||
disabled={boardHistory.length === 0}
|
<IconButton
|
||||||
>
|
onClick={() => boardActions.reset()}
|
||||||
<Icon icon="ri:skip-back-line" />
|
disabled={boardHistory.length === 0}
|
||||||
</IconButton>
|
>
|
||||||
|
<Icon icon="ri:skip-back-line" />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
<IconButton
|
<Tooltip title="Go to previous move">
|
||||||
onClick={() => boardActions.undo()}
|
<Grid>
|
||||||
disabled={boardHistory.length === 0}
|
<IconButton
|
||||||
>
|
onClick={() => boardActions.undo()}
|
||||||
<Icon icon="ri:arrow-left-s-line" height={30} />
|
disabled={boardHistory.length === 0}
|
||||||
</IconButton>
|
>
|
||||||
|
<Icon icon="ri:arrow-left-s-line" height={30} />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
<NextMoveButton />
|
<NextMoveButton />
|
||||||
|
|
||||||
@@ -41,6 +62,37 @@ export default function ReviewPanelToolBar() {
|
|||||||
|
|
||||||
<SaveButton />
|
<SaveButton />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
item
|
||||||
|
justifyContent="space-evenly"
|
||||||
|
alignItems="center"
|
||||||
|
xs={12}
|
||||||
|
marginY={3}
|
||||||
|
gap={3}
|
||||||
|
>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={showBestMove}
|
||||||
|
onChange={(_, checked) => setShowBestMove(checked)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Show best move green arrow"
|
||||||
|
sx={{ marginX: 0 }}
|
||||||
|
/>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={showPlayerMove}
|
||||||
|
onChange={(_, checked) => setShowPlayerMove(checked)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Show player move yellow arrow"
|
||||||
|
sx={{ marginX: 0 }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { IconButton } from "@mui/material";
|
import { Grid, IconButton, Tooltip } from "@mui/material";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { boardAtom, gameAtom } from "../states";
|
import { boardAtom, gameAtom } from "../states";
|
||||||
import { useChessActions } from "@/hooks/useChess";
|
import { useChessActions } from "@/hooks/useChess";
|
||||||
@@ -32,11 +32,15 @@ export default function NextMoveButton() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<Tooltip title="Go to next move">
|
||||||
onClick={() => addNextGameMoveToBoard()}
|
<Grid>
|
||||||
disabled={!isButtonEnabled}
|
<IconButton
|
||||||
>
|
onClick={() => addNextGameMoveToBoard()}
|
||||||
<Icon icon="ri:arrow-right-s-line" height={30} />
|
disabled={!isButtonEnabled}
|
||||||
</IconButton>
|
>
|
||||||
|
<Icon icon="ri:arrow-right-s-line" height={30} />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
import { useGameDatabase } from "@/hooks/useGameDatabase";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { IconButton } from "@mui/material";
|
import { Grid, IconButton, Tooltip } from "@mui/material";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { boardAtom, gameAtom, gameEvalAtom } from "../states";
|
import { boardAtom, gameAtom, gameEvalAtom } from "../states";
|
||||||
@@ -39,13 +39,21 @@ export default function SaveButton() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{gameFromUrl ? (
|
{gameFromUrl ? (
|
||||||
<IconButton disabled={true}>
|
<Tooltip title="Game saved in database">
|
||||||
<Icon icon="ri:folder-check-line" />
|
<Grid>
|
||||||
</IconButton>
|
<IconButton disabled={true}>
|
||||||
|
<Icon icon="ri:folder-check-line" />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<IconButton onClick={handleSave} disabled={!enableSave}>
|
<Tooltip title="Save game">
|
||||||
<Icon icon="ri:save-3-line" />
|
<Grid>
|
||||||
</IconButton>
|
<IconButton onClick={handleSave} disabled={!enableSave}>
|
||||||
|
<Icon icon="ri:save-3-line" />
|
||||||
|
</IconButton>
|
||||||
|
</Grid>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ import { atom } from "jotai";
|
|||||||
export const gameEvalAtom = atom<GameEval | undefined>(undefined);
|
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 showBestMoveArrowAtom = atom(true);
|
||||||
|
export const showPlayerMoveArrowAtom = atom(true);
|
||||||
|
|
||||||
export const engineDepthAtom = atom(16);
|
export const engineDepthAtom = atom(16);
|
||||||
export const engineMultiPvAtom = atom(3);
|
export const engineMultiPvAtom = atom(3);
|
||||||
|
|||||||
Reference in New Issue
Block a user