diff --git a/src/components/board/constants.ts b/src/components/board/constants.ts deleted file mode 100644 index f17e0ac..0000000 --- a/src/components/board/constants.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Piece } from "react-chessboard/dist/chessboard/types"; - -export const PIECE_CODES = [ - "wP", - "wB", - "wN", - "wR", - "wQ", - "wK", - "bP", - "bB", - "bN", - "bR", - "bQ", - "bK", -] as const satisfies Piece[]; - -export const PIECE_SETS = [ - "alpha", - "anarcandy", - "caliente", - "california", - "cardinal", - "cburnett", - "celtic", - "chess7", - "chessnut", - "companion", - "cooke", - "dubrovny", - "fantasy", - "firi", - "fresca", - "gioco", - "governor", - "horsey", - "icpieces", - "kiwen-suwi", - "kosal", - "leipzig", - "letter", - "maestro", - "merida", - "monarchy", - "mpchess", - "pirouetti", - "pixel", - "reillycraig", - "rhosgfx", - "riohacha", - "shapes", - "spatial", - "staunty", - "tatiana", - "xkcd", -] as const satisfies string[]; diff --git a/src/components/board/index.tsx b/src/components/board/index.tsx index 6f5a727..8084535 100644 --- a/src/components/board/index.tsx +++ b/src/components/board/index.tsx @@ -5,6 +5,7 @@ import { Arrow, CustomPieces, CustomSquareRenderer, + Piece, PromotionPieceOption, Square, } from "react-chessboard/dist/chessboard/types"; @@ -15,13 +16,12 @@ import { Chess } from "chess.js"; import { getSquareRenderer } from "./squareRenderer"; import { CurrentPosition } from "@/types/eval"; import EvaluationBar from "./evaluationBar"; -import { moveClassificationColors } from "@/lib/chess"; +import { CLASSIFICATION_COLORS } from "@/constants"; import { Player } from "@/types/game"; import PlayerHeader from "./playerHeader"; import Image from "next/image"; import { boardHueAtom, pieceSetAtom } from "./states"; import tinycolor from "tinycolor2"; -import { PIECE_CODES } from "./constants"; export interface Props { id: string; @@ -52,7 +52,7 @@ export default function Board({ }: Props) { const boardRef = useRef(null); const game = useAtomValue(gameAtom); - const { makeMove: makeGameMove } = useChessActions(gameAtom); + const { playMove } = useChessActions(gameAtom); const clickedSquaresAtom = useMemo(() => atom([]), []); const setClickedSquares = useSetAtom(clickedSquaresAtom); const playableSquaresAtom = useMemo(() => atom([]), []); @@ -86,7 +86,7 @@ export default function Board({ ): boolean => { if (!isPiecePlayable({ piece })) return false; - const result = makeGameMove({ + const result = playMove({ from: source, to: target, promotion: piece[1]?.toLowerCase() ?? "q", @@ -135,7 +135,7 @@ export default function Board({ return; } - const result = makeGameMove({ + const result = playMove({ from: moveClickFrom, to: square, }); @@ -168,7 +168,7 @@ export default function Board({ const promotionPiece = piece[1]?.toLowerCase() ?? "q"; if (moveClickFrom && moveClickTo) { - const result = makeGameMove({ + const result = playMove({ from: moveClickFrom, to: moveClickTo, promotion: promotionPiece, @@ -178,7 +178,7 @@ export default function Board({ } if (from && to) { - const result = makeGameMove({ + const result = playMove({ from, to, promotion: promotionPiece, @@ -206,7 +206,7 @@ export default function Board({ const bestMoveArrow = [ bestMove.slice(0, 2), bestMove.slice(2, 4), - tinycolor(moveClassificationColors[MoveClassification.Best]) + tinycolor(CLASSIFICATION_COLORS[MoveClassification.Best]) .spin(-boardHue) .toHexString(), ] as Arrow; @@ -325,3 +325,18 @@ export default function Board({ ); } + +export const PIECE_CODES = [ + "wP", + "wB", + "wN", + "wR", + "wQ", + "wK", + "bP", + "bB", + "bN", + "bR", + "bQ", + "bK", +] as const satisfies Piece[]; diff --git a/src/components/board/squareRenderer.tsx b/src/components/board/squareRenderer.tsx index fb3808f..4e4454c 100644 --- a/src/components/board/squareRenderer.tsx +++ b/src/components/board/squareRenderer.tsx @@ -7,7 +7,7 @@ import { CustomSquareProps, Square, } from "react-chessboard/dist/chessboard/types"; -import { moveClassificationColors } from "@/lib/chess"; +import { CLASSIFICATION_COLORS } from "@/constants"; import { boardHueAtom } from "./states"; export interface Props { @@ -110,7 +110,7 @@ const previousMoveSquareStyle = ( width: "100%", height: "100%", backgroundColor: moveClassification - ? moveClassificationColors[moveClassification] + ? CLASSIFICATION_COLORS[moveClassification] : "#fad541", opacity: 0.5, }); diff --git a/src/components/board/states.ts b/src/components/board/states.ts index 4ffce8e..a2065f9 100644 --- a/src/components/board/states.ts +++ b/src/components/board/states.ts @@ -1,5 +1,5 @@ +import { PIECE_SETS } from "@/constants"; import { atomWithStorage } from "jotai/utils"; -import { PIECE_SETS } from "./constants"; export const pieceSetAtom = atomWithStorage<(typeof PIECE_SETS)[number]>( "pieceSet", diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..021989b --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,91 @@ +import { EngineName, MoveClassification } from "./types/enums"; + +export const CLASSIFICATION_COLORS: Record = { + [MoveClassification.Book]: "#d5a47d", + [MoveClassification.Forced]: "#d5a47d", + [MoveClassification.Brilliant]: "#26c2a3", + [MoveClassification.Great]: "#4099ed", + [MoveClassification.Best]: "#3aab18", + [MoveClassification.Excellent]: "#3aab18", + [MoveClassification.Good]: "#81b64c", + [MoveClassification.Inaccuracy]: "#f7c631", + [MoveClassification.Mistake]: "#ffa459", + [MoveClassification.Blunder]: "#fa412d", +}; + +export const DEFAULT_ENGINE: EngineName = EngineName.Stockfish17Lite; +export const STRONGEST_ENGINE: EngineName = EngineName.Stockfish17; + +export const ENGINE_LABELS: Record< + EngineName, + { small: string; full: string } +> = { + [EngineName.Stockfish17]: { + full: "Stockfish 17 (75MB)", + small: "Stockfish 17", + }, + [EngineName.Stockfish17Lite]: { + full: "Stockfish 17 Lite (6MB)", + small: "Stockfish 17 Lite", + }, + [EngineName.Stockfish16_1]: { + full: "Stockfish 16.1 (64MB)", + small: "Stockfish 16.1", + }, + [EngineName.Stockfish16_1Lite]: { + full: "Stockfish 16.1 Lite (6MB)", + small: "Stockfish 16.1 Lite", + }, + [EngineName.Stockfish16NNUE]: { + full: "Stockfish 16 (40MB)", + small: "Stockfish 16", + }, + [EngineName.Stockfish16]: { + full: "Stockfish 16 Lite (HCE)", + small: "Stockfish 16 Lite", + }, + [EngineName.Stockfish11]: { + full: "Stockfish 11 (HCE)", + small: "Stockfish 11", + }, +}; + +export const PIECE_SETS = [ + "alpha", + "anarcandy", + "caliente", + "california", + "cardinal", + "cburnett", + "celtic", + "chess7", + "chessnut", + "companion", + "cooke", + "dubrovny", + "fantasy", + "firi", + "fresca", + "gioco", + "governor", + "horsey", + "icpieces", + "kiwen-suwi", + "kosal", + "leipzig", + "letter", + "maestro", + "merida", + "monarchy", + "mpchess", + "pirouetti", + "pixel", + "reillycraig", + "rhosgfx", + "riohacha", + "shapes", + "spatial", + "staunty", + "tatiana", + "xkcd", +] as const satisfies string[]; diff --git a/src/hooks/useChessActions.ts b/src/hooks/useChessActions.ts index 3efdfd2..b7d4e92 100644 --- a/src/hooks/useChessActions.ts +++ b/src/hooks/useChessActions.ts @@ -67,7 +67,7 @@ export const useChessActions = (chessAtom: PrimitiveAtom) => { [copyGame, setGame] ); - const makeMove = useCallback( + const playMove = useCallback( (params: { from: string; to: string; @@ -92,6 +92,18 @@ export const useChessActions = (chessAtom: PrimitiveAtom) => { [copyGame, setGame] ); + const addMoves = useCallback( + (moves: string[]) => { + const newGame = copyGame(); + + for (const move of moves) { + newGame.move(move); + } + setGame(newGame); + }, + [copyGame, setGame] + ); + const undoMove = useCallback(() => { const newGame = copyGame(); const move = newGame.undo(); @@ -127,9 +139,10 @@ export const useChessActions = (chessAtom: PrimitiveAtom) => { return { setPgn, reset, - makeMove, + playMove, undoMove, goToMove, resetToStartingPosition, + addMoves, }; }; diff --git a/src/lib/chess.ts b/src/lib/chess.ts index a9a9baf..2f9907e 100644 --- a/src/lib/chess.ts +++ b/src/lib/chess.ts @@ -2,7 +2,7 @@ import { EvaluateGameParams, LineEval, PositionEval } from "@/types/eval"; import { Game, Player } from "@/types/game"; import { Chess, PieceSymbol, Square } from "chess.js"; import { getPositionWinPercentage } from "./engine/helpers/winPercentage"; -import { Color, MoveClassification } from "@/types/enums"; +import { Color } from "@/types/enums"; export const getEvaluateGameParams = (game: Chess): EvaluateGameParams => { const history = game.history({ verbose: true }); @@ -327,15 +327,33 @@ export const getLineEvalLabel = ( return "?"; }; -export const moveClassificationColors: Record = { - [MoveClassification.Book]: "#d5a47d", - [MoveClassification.Forced]: "#d5a47d", - [MoveClassification.Brilliant]: "#26c2a3", - [MoveClassification.Great]: "#4099ed", - [MoveClassification.Best]: "#3aab18", - [MoveClassification.Excellent]: "#3aab18", - [MoveClassification.Good]: "#81b64c", - [MoveClassification.Inaccuracy]: "#f7c631", - [MoveClassification.Mistake]: "#ffa459", - [MoveClassification.Blunder]: "#fa412d", +export const formatUciPv = (fen: string, uciMoves: string[]): string[] => { + const castlingRights = fen.split(" ")[2]; + + let canWhiteCastleKingSide = castlingRights.includes("K"); + let canWhiteCastleQueenSide = castlingRights.includes("Q"); + let canBlackCastleKingSide = castlingRights.includes("k"); + let canBlackCastleQueenSide = castlingRights.includes("q"); + + return uciMoves.map((uci) => { + if (uci === "e1h1" && canWhiteCastleKingSide) { + canWhiteCastleKingSide = false; + return "e1g1"; + } + if (uci === "e1a1" && canWhiteCastleQueenSide) { + canWhiteCastleQueenSide = false; + return "e1c1"; + } + + if (uci === "e8h8" && canBlackCastleKingSide) { + canBlackCastleKingSide = false; + return "e8g8"; + } + if (uci === "e8a8" && canBlackCastleQueenSide) { + canBlackCastleQueenSide = false; + return "e8c8"; + } + + return uci; + }); }; diff --git a/src/lib/engine/helpers/parseResults.ts b/src/lib/engine/helpers/parseResults.ts index d2eee90..6784dea 100644 --- a/src/lib/engine/helpers/parseResults.ts +++ b/src/lib/engine/helpers/parseResults.ts @@ -1,8 +1,9 @@ +import { formatUciPv } from "@/lib/chess"; import { LineEval, PositionEval } from "@/types/eval"; export const parseEvaluationResults = ( results: string[], - whiteToPlay: boolean + fen: string ): PositionEval => { const parsedResults: PositionEval = { lines: [], @@ -18,7 +19,7 @@ export const parseEvaluationResults = ( } if (result.startsWith("info")) { - const pv = getResultPv(result); + const pv = getResultPv(result, fen); const multiPv = getResultProperty(result, "multipv"); const depth = getResultProperty(result, "depth"); if (!pv || !multiPv || !depth) continue; @@ -45,6 +46,7 @@ export const parseEvaluationResults = ( parsedResults.lines = Object.values(tempResults).sort(sortLines); + const whiteToPlay = fen.split(" ")[1] === "w"; if (!whiteToPlay) { parsedResults.lines = parsedResults.lines.map((line) => ({ ...line, @@ -86,7 +88,7 @@ export const getResultProperty = ( return splitResult[propertyIndex + 1]; }; -const getResultPv = (result: string): string[] | undefined => { +const getResultPv = (result: string, fen: string): string[] | undefined => { const splitResult = result.split(" "); const pvIndex = splitResult.indexOf("pv"); @@ -94,5 +96,6 @@ const getResultPv = (result: string): string[] | undefined => { return undefined; } - return splitResult.slice(pvIndex + 1); + const rawPv = splitResult.slice(pvIndex + 1); + return formatUciPv(fen, rawPv); }; diff --git a/src/lib/engine/uciEngine.ts b/src/lib/engine/uciEngine.ts index d9babdc..ff6e0be 100644 --- a/src/lib/engine/uciEngine.ts +++ b/src/lib/engine/uciEngine.ts @@ -317,9 +317,7 @@ export class UciEngine { "bestmove" ); - const whiteToPlay = fen.split(" ")[1] === "w"; - - return parseEvaluationResults(results, whiteToPlay); + return parseEvaluationResults(results, fen); } public async evaluatePositionWithUpdate({ @@ -335,11 +333,9 @@ export class UciEngine { await this.stopSearch(); await this.setMultiPv(multiPv); - const whiteToPlay = fen.split(" ")[1] === "w"; - const onNewMessage = (messages: string[]) => { if (!setPartialEval) return; - const parsedResults = parseEvaluationResults(messages, whiteToPlay); + const parsedResults = parseEvaluationResults(messages, fen); setPartialEval(parsedResults); }; @@ -360,7 +356,7 @@ export class UciEngine { onNewMessage ); - return parseEvaluationResults(results, whiteToPlay); + return parseEvaluationResults(results, fen); } public async getEngineNextMove( diff --git a/src/lib/lichess.ts b/src/lib/lichess.ts index cef22d6..222dd0c 100644 --- a/src/lib/lichess.ts +++ b/src/lib/lichess.ts @@ -7,6 +7,7 @@ import { LichessResponse, } from "@/types/lichess"; import { logErrorToSentry } from "./sentry"; +import { formatUciPv } from "./chess"; export const getLichessEval = async ( fen: string, @@ -26,7 +27,7 @@ export const getLichessEval = async ( } const lines: LineEval[] = data.pvs.map((pv, index) => ({ - pv: pv.moves.split(" "), + pv: formatUciPv(fen, pv.moves.split(" ")), cp: pv.cp, mate: pv.mate, depth: data.depth, diff --git a/src/sections/analysis/panelBody/analysisTab/chess_merida_unicode.ttf b/src/sections/analysis/panelBody/analysisTab/chess_merida_unicode.ttf new file mode 100644 index 0000000..674af6b Binary files /dev/null and b/src/sections/analysis/panelBody/analysisTab/chess_merida_unicode.ttf differ diff --git a/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx b/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx index 4cf23b8..6297934 100644 --- a/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx +++ b/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx @@ -1,15 +1,23 @@ import { LineEval } from "@/types/eval"; -import { ListItem, Skeleton, Typography } from "@mui/material"; +import { Box, ListItem, Skeleton, Typography, useTheme } from "@mui/material"; import { useAtomValue } from "jotai"; import { boardAtom } from "../../states"; import { getLineEvalLabel, moveLineUciToSan } from "@/lib/chess"; +import localFont from "next/font/local"; +import { useChessActions } from "@/hooks/useChessActions"; + +const myFont = localFont({ + src: "./chess_merida_unicode.ttf", +}); interface Props { line: LineEval; } export default function LineEvaluation({ line }: Props) { + const theme = useTheme(); const board = useAtomValue(boardAtom); + const { addMoves } = useChessActions(boardAtom); const lineLabel = getLineEvalLabel(line); const isBlackCp = @@ -18,6 +26,26 @@ export default function LineEvaluation({ line }: Props) { const showSkeleton = line.depth < 6; + const uciToSan = moveLineUciToSan(board.fen()); + const initialTurn = board.turn(); + const isDarkMode = theme.palette.mode === "dark"; + + const formatSan = ( + san: string, + moveIdx: number + ): { icon?: string; text: string } => { + const firstChar = san.charAt(0); + + const isPiece = ["K", "Q", "R", "B", "N"].includes(firstChar); + if (!isPiece) return { text: san }; + + const turn = isDarkMode ? initialTurn : initialTurn === "w" ? "b" : "w"; + const moveColor = moveIdx % 2 === 0 ? turn : turn === "w" ? "b" : "w"; + const icon = unicodeMap[firstChar][moveColor]; + + return { icon, text: san.slice(1) }; + }; + return ( ) : ( - line.pv.map(moveLineUciToSan(board.fen())).join(", ") + line.pv.map((uci, i) => { + const san = uciToSan(uci); + const { icon, text } = formatSan(san, i); + + return ( + { + addMoves(line.pv.slice(0, i + 1)); + }} + sx={{ + cursor: "pointer", + ml: i ? 0.5 : 0, + transition: "opacity 0.2s ease-in-out", + "&:hover": { + opacity: 0.5, + }, + }} + > + {icon && ( + + {icon} + + )} + + + {text} + {i < line.pv.length - 1 && ","} + + + ); + }) )} ); } + +const unicodeMap: Record> = { + K: { w: "♚", b: "♔" }, + Q: { w: "♛", b: "♕" }, + R: { w: "♜", b: "♖" }, + B: { w: "♝", b: "♗" }, + N: { w: "♞", b: "♘" }, +}; diff --git a/src/sections/analysis/panelBody/classificationTab/movesClassificationsRecap/classificationRow.tsx b/src/sections/analysis/panelBody/classificationTab/movesClassificationsRecap/classificationRow.tsx index e30936f..cf783e6 100644 --- a/src/sections/analysis/panelBody/classificationTab/movesClassificationsRecap/classificationRow.tsx +++ b/src/sections/analysis/panelBody/classificationTab/movesClassificationsRecap/classificationRow.tsx @@ -6,7 +6,7 @@ import { useMemo } from "react"; import Image from "next/image"; import { capitalize } from "@/lib/helpers"; import { useChessActions } from "@/hooks/useChessActions"; -import { moveClassificationColors } from "@/lib/chess"; +import { CLASSIFICATION_COLORS } from "@/constants"; interface Props { classification: MoveClassification; @@ -74,7 +74,7 @@ export default function ClassificationRow({ classification }: Props) { justifyContent="space-evenly" alignItems="center" wrap="nowrap" - color={moveClassificationColors[classification]} + color={CLASSIFICATION_COLORS[classification]} size={12} > { return undefined; } - return moveClassificationColors[moveClassification]; + return CLASSIFICATION_COLORS[moveClassification]; }; const moveClassificationsToIgnore: MoveClassification[] = [ diff --git a/src/sections/analysis/panelBody/graphTab/dot.tsx b/src/sections/analysis/panelBody/graphTab/dot.tsx index 1a81efd..9876686 100644 --- a/src/sections/analysis/panelBody/graphTab/dot.tsx +++ b/src/sections/analysis/panelBody/graphTab/dot.tsx @@ -1,6 +1,6 @@ import { DotProps } from "recharts"; import { ChartItemData } from "./types"; -import { moveClassificationColors } from "@/lib/chess"; +import { CLASSIFICATION_COLORS } from "@/constants"; export default function CustomDot({ cx, @@ -9,7 +9,7 @@ export default function CustomDot({ payload, }: DotProps & { payload?: ChartItemData }) { const moveColor = payload?.moveClassification - ? moveClassificationColors[payload.moveClassification] + ? CLASSIFICATION_COLORS[payload.moveClassification] : "grey"; return ( diff --git a/src/sections/analysis/panelBody/graphTab/index.tsx b/src/sections/analysis/panelBody/graphTab/index.tsx index 2a84be2..71a98b1 100644 --- a/src/sections/analysis/panelBody/graphTab/index.tsx +++ b/src/sections/analysis/panelBody/graphTab/index.tsx @@ -21,7 +21,7 @@ import type { ReactElement } from "react"; import CustomTooltip from "./tooltip"; import { ChartItemData } from "./types"; import { PositionEval } from "@/types/eval"; -import { moveClassificationColors } from "@/lib/chess"; +import { CLASSIFICATION_COLORS } from "@/constants"; import CustomDot from "./dot"; import { MoveClassification } from "@/types/enums"; import { useChessActions } from "@/hooks/useChessActions"; @@ -51,7 +51,7 @@ export default function GraphTab(props: GridProps) { }, [chartData]); const boardMoveColor = currentPosition.eval?.moveClassification - ? moveClassificationColors[currentPosition.eval.moveClassification] + ? CLASSIFICATION_COLORS[currentPosition.eval.moveClassification] : "grey"; // Render a dot only on selected classifications (always returns an element) diff --git a/src/sections/analysis/panelToolbar/nextMoveButton.tsx b/src/sections/analysis/panelToolbar/nextMoveButton.tsx index bad16d0..8691f44 100644 --- a/src/sections/analysis/panelToolbar/nextMoveButton.tsx +++ b/src/sections/analysis/panelToolbar/nextMoveButton.tsx @@ -6,7 +6,7 @@ import { useChessActions } from "@/hooks/useChessActions"; import { useCallback, useEffect } from "react"; export default function NextMoveButton() { - const { makeMove: makeBoardMove } = useChessActions(boardAtom); + const { playMove: playBoardMove } = useChessActions(boardAtom); const game = useAtomValue(gameAtom); const board = useAtomValue(boardAtom); @@ -27,14 +27,14 @@ export default function NextMoveButton() { .find((c) => c.fen === nextMove.after)?.comment; if (nextMove) { - makeBoardMove({ + playBoardMove({ from: nextMove.from, to: nextMove.to, promotion: nextMove.promotion, comment, }); } - }, [isButtonEnabled, boardHistory, game, makeBoardMove]); + }, [isButtonEnabled, boardHistory, game, playBoardMove]); useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { diff --git a/src/sections/analysis/states.ts b/src/sections/analysis/states.ts index ff59887..17b5203 100644 --- a/src/sections/analysis/states.ts +++ b/src/sections/analysis/states.ts @@ -1,3 +1,4 @@ +import { DEFAULT_ENGINE } from "@/constants"; import { EngineName } from "@/types/enums"; import { CurrentPosition, GameEval, SavedEvals } from "@/types/eval"; import { Chess } from "chess.js"; @@ -12,7 +13,7 @@ export const boardOrientationAtom = atom(true); export const showBestMoveArrowAtom = atom(true); export const showPlayerMoveIconAtom = atom(true); -export const engineNameAtom = atom(EngineName.Stockfish17Lite); +export const engineNameAtom = atom(DEFAULT_ENGINE); export const engineDepthAtom = atom(14); export const engineMultiPvAtom = atom(3); export const evaluationProgressAtom = atom(0); diff --git a/src/sections/engineSettings/engineSettingsDialog.tsx b/src/sections/engineSettings/engineSettingsDialog.tsx index ca0ddc3..4cf19fb 100644 --- a/src/sections/engineSettings/engineSettingsDialog.tsx +++ b/src/sections/engineSettings/engineSettingsDialog.tsx @@ -26,7 +26,12 @@ import { isEngineSupported } from "@/lib/engine/shared"; import { Stockfish16_1 } from "@/lib/engine/stockfish16_1"; import { useAtom } from "jotai"; import { boardHueAtom, pieceSetAtom } from "@/components/board/states"; -import { PIECE_SETS } from "@/components/board/constants"; +import { + DEFAULT_ENGINE, + ENGINE_LABELS, + PIECE_SETS, + STRONGEST_ENGINE, +} from "@/constants"; interface Props { open: boolean; @@ -76,10 +81,11 @@ export default function EngineSettingsDialog({ open, onClose }: Props) { size={{ xs: 12, sm: 7, md: 8 }} > - Stockfish 17 Lite is the default engine if your device support its - requirements. It offers the best balance between speed and - strength. Stockfish 17 is the strongest engine available, note - that it requires a one time download of 75MB. + {ENGINE_LABELS[DEFAULT_ENGINE].small} is the default engine if + your device support its requirements. It offers the best balance + between speed and strength.{" "} + {ENGINE_LABELS[STRONGEST_ENGINE].small} is the strongest engine + available, note that it requires a one time download of 75MB. @@ -105,7 +111,7 @@ export default function EngineSettingsDialog({ open, onClose }: Props) { value={engine} disabled={!isEngineSupported(engine)} > - {engineLabel[engine].full} + {ENGINE_LABELS[engine].full} ))} @@ -183,35 +189,3 @@ export default function EngineSettingsDialog({ open, onClose }: Props) { ); } - -export const engineLabel: Record = - { - [EngineName.Stockfish17]: { - full: "Stockfish 17 (75MB)", - small: "Stockfish 17", - }, - [EngineName.Stockfish17Lite]: { - full: "Stockfish 17 Lite (6MB)", - small: "Stockfish 17 Lite", - }, - [EngineName.Stockfish16_1]: { - full: "Stockfish 16.1 (64MB)", - small: "Stockfish 16.1", - }, - [EngineName.Stockfish16_1Lite]: { - full: "Stockfish 16.1 Lite (6MB)", - small: "Stockfish 16.1 Lite", - }, - [EngineName.Stockfish16NNUE]: { - full: "Stockfish 16 (40MB)", - small: "Stockfish 16", - }, - [EngineName.Stockfish16]: { - full: "Stockfish 16 Lite (HCE)", - small: "Stockfish 16 Lite", - }, - [EngineName.Stockfish11]: { - full: "Stockfish 11 (HCE)", - small: "Stockfish 11", - }, - }; diff --git a/src/sections/play/board.tsx b/src/sections/play/board.tsx index 742705d..4fdac6e 100644 --- a/src/sections/play/board.tsx +++ b/src/sections/play/board.tsx @@ -23,7 +23,7 @@ export default function BoardContainer() { const game = useAtomValue(gameAtom); const { white, black } = usePlayersData(gameAtom); const playerColor = useAtomValue(playerColorAtom); - const { makeMove: makeGameMove } = useChessActions(gameAtom); + const { playMove } = useChessActions(gameAtom); const engineElo = useAtomValue(engineEloAtom); const isGameInProgress = useAtomValue(isGameInProgressAtom); @@ -41,7 +41,7 @@ export default function BoardContainer() { return; } const move = await engine.getEngineNextMove(gameFen, engineElo); - if (move) makeGameMove(uciMoveParams(move)); + if (move) playMove(uciMoveParams(move)); }; playEngineMove(); diff --git a/src/sections/play/gameSettings/gameSettingsDialog.tsx b/src/sections/play/gameSettings/gameSettingsDialog.tsx index 8102d7d..8524316 100644 --- a/src/sections/play/gameSettings/gameSettingsDialog.tsx +++ b/src/sections/play/gameSettings/gameSettingsDialog.tsx @@ -32,7 +32,7 @@ import { logAnalyticsEvent } from "@/lib/firebase"; import { useEffect } from "react"; import { isEngineSupported } from "@/lib/engine/shared"; import { Stockfish16_1 } from "@/lib/engine/stockfish16_1"; -import { engineLabel } from "@/sections/engineSettings/engineSettingsDialog"; +import { DEFAULT_ENGINE, ENGINE_LABELS, STRONGEST_ENGINE } from "@/constants"; interface Props { open: boolean; @@ -57,12 +57,12 @@ export default function GameSettingsDialog({ open, onClose }: Props) { resetGame({ white: { name: - playerColor === Color.White ? "You" : engineLabel[engineName].small, + playerColor === Color.White ? "You" : ENGINE_LABELS[engineName].small, rating: playerColor === Color.White ? undefined : engineElo, }, black: { name: - playerColor === Color.Black ? "You" : engineLabel[engineName].small, + playerColor === Color.Black ? "You" : ENGINE_LABELS[engineName].small, rating: playerColor === Color.Black ? undefined : engineElo, }, }); @@ -93,10 +93,11 @@ export default function GameSettingsDialog({ open, onClose }: Props) { - Stockfish 17 Lite is the default engine if your device support its - requirements. It offers the best balance between speed and strength. - Stockfish 17 is the strongest engine available, note that it requires - a one time download of 75MB. + {ENGINE_LABELS[DEFAULT_ENGINE].small} is the default engine if your + device support its requirements. It offers the best balance between + speed and strength. {ENGINE_LABELS[STRONGEST_ENGINE].small} is the + strongest engine available, note that it requires a one time download + of 75MB. - {engineLabel[engine].full} + {ENGINE_LABELS[engine].full} ))} diff --git a/src/sections/play/states.ts b/src/sections/play/states.ts index edfe070..d12ec93 100644 --- a/src/sections/play/states.ts +++ b/src/sections/play/states.ts @@ -1,3 +1,4 @@ +import { DEFAULT_ENGINE } from "@/constants"; import { Color, EngineName } from "@/types/enums"; import { CurrentPosition } from "@/types/eval"; import { Chess } from "chess.js"; @@ -6,6 +7,6 @@ import { atom } from "jotai"; export const gameAtom = atom(new Chess()); export const gameDataAtom = atom({}); export const playerColorAtom = atom(Color.White); -export const enginePlayNameAtom = atom(EngineName.Stockfish17Lite); +export const enginePlayNameAtom = atom(DEFAULT_ENGINE); export const engineEloAtom = atom(1320); export const isGameInProgressAtom = atom(false);