From ea28844d9337f7af6813a39c6fc577a82d7bff66 Mon Sep 17 00:00:00 2001 From: GuillaumeSD Date: Sun, 25 May 2025 18:16:43 +0200 Subject: [PATCH] feat : new captured piece icons --- README.md | 6 +- public/captured-pieces.png | Bin 19937 -> 0 bytes src/components/board/capturedPieces.tsx | 166 ++++++------------------ src/lib/chess.ts | 68 +++++++--- src/sections/layout/index.tsx | 2 +- 5 files changed, 91 insertions(+), 151 deletions(-) delete mode 100644 public/captured-pieces.png diff --git a/README.md b/README.md index 7794572..edb0564 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,15 @@
-Chesskit is an open-source chess web app to play, view and analyze your chess games for free on any device with Stockfish ! +Chesskit is an open-source chess website to play, view, analyze and review your chess games for free on any device with Stockfish ! ## Mission -It aims to offer all the features it can from the best chess apps, while being free and open-source. It is designed to be easy to use, fast, and reliable. +Chesskit aims to offer all the chess related features it can, while being free and open-source. It is designed to be easy to use, fast, and reliable. ## Features -- Load and analyze games from [chess.com](https://chess.com) and [lichess.org](https://lichess.org) +- Load and review games from [chess.com](https://chess.com) and [lichess.org](https://lichess.org) - Analysis board with live engine evaluation, custom arrows, evaluation graph, ... - Moves classification (Brilliant, Great, Good, Mistake, Blunder, ...) - Chess960 and Puzzles support diff --git a/public/captured-pieces.png b/public/captured-pieces.png deleted file mode 100644 index 9caaad9e36f43a1dbb9a8f0c159e3471fd4e6b60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19937 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 XB>MR)(_Wq@J|kGs?JP=YZqdI3eivGN diff --git a/src/components/board/capturedPieces.tsx b/src/components/board/capturedPieces.tsx index 4c612a5..39e1f18 100644 --- a/src/components/board/capturedPieces.tsx +++ b/src/components/board/capturedPieces.tsx @@ -1,7 +1,7 @@ import { getCapturedPieces, getMaterialDifference } from "@/lib/chess"; import { Color } from "@/types/enums"; -import { Grid2 as Grid, Typography } from "@mui/material"; -import { CSSProperties, useMemo } from "react"; +import { Box, Grid2 as Grid, Stack, Typography } from "@mui/material"; +import { ReactElement, useMemo } from "react"; export interface Props { fen: string; @@ -11,9 +11,11 @@ export interface Props { const PIECE_SCALE = 0.55; export default function CapturedPieces({ fen, color }: Props) { - const cssProps = useMemo(() => { + const piecesComponents = useMemo(() => { const capturedPieces = getCapturedPieces(fen, color); - return getCapturedPiecesCSSProps(capturedPieces, color); + return capturedPieces.map(({ piece, count }) => + getCapturedPiecesComponents(piece, count) + ); }, [fen, color]); const materialDiff = useMemo(() => { @@ -22,19 +24,16 @@ export default function CapturedPieces({ fen, color }: Props) { }, [fen, color]); return ( - - {cssProps.map((cssProp, i) => ( - - ))} + + + {piecesComponents} + {materialDiff > 0 && ( , - color: Color -): CSSProperties[] => { - const cssProps: CSSProperties[] = []; +const getCapturedPiecesComponents = ( + pieceSymbol: string, + pieceCount: number | undefined +): ReactElement | null => { + if (!pieceCount) return null; - if (color === Color.Black) { - if (capturedPieces.P) { - cssProps.push({ - backgroundPositionX: `-${18 * PIECE_SCALE}rem`, - backgroundPositionY: `${ - -20.1 * PIECE_SCALE + capturedPieces.P * 2.5 * PIECE_SCALE - }rem`, - width: `${0.6 * PIECE_SCALE + capturedPieces.P * 0.7 * PIECE_SCALE}rem`, - height: `${1.7 * PIECE_SCALE}rem`, - }); - } - - if (capturedPieces.B) { - cssProps.push({ - backgroundPosition: `-${24.7 * PIECE_SCALE}rem ${ - -5.1 * PIECE_SCALE + capturedPieces.B * 2.6 * PIECE_SCALE - }rem`, - width: `${0.7 * PIECE_SCALE + capturedPieces.B * 0.8 * PIECE_SCALE}rem`, - height: `${ - 1.7 * PIECE_SCALE + capturedPieces.B * 0.1 * PIECE_SCALE - }rem`, - }); - } - - if (capturedPieces.N) { - cssProps.push({ - backgroundPosition: `-${27.5 * PIECE_SCALE}rem ${ - -4.9 * PIECE_SCALE + capturedPieces.N * 2.5 * PIECE_SCALE - }rem`, - width: `${0.9 * PIECE_SCALE + capturedPieces.N * 0.7 * PIECE_SCALE}rem`, - height: `${1.9 * PIECE_SCALE}rem`, - }); - } - - if (capturedPieces.R) { - cssProps.push({ - backgroundPosition: `${ - -30.2 * PIECE_SCALE + capturedPieces.R * 0.1 * PIECE_SCALE - }rem ${-5.1 * PIECE_SCALE + capturedPieces.R * 2.5 * PIECE_SCALE}rem`, - width: `${0.7 * PIECE_SCALE + capturedPieces.R * 0.8 * PIECE_SCALE}rem`, - height: `${1.7 * PIECE_SCALE}rem`, - }); - } - - if (capturedPieces.Q) { - cssProps.push({ - backgroundPosition: `-${32.5 * PIECE_SCALE}rem ${0.1 * PIECE_SCALE}rem`, - width: `${1.8 * PIECE_SCALE}rem`, - height: `${1.9 * PIECE_SCALE}rem`, - }); - } - } else { - if (capturedPieces.p) { - cssProps.push({ - backgroundPositionX: 0, - backgroundPositionY: `${ - -20.1 * PIECE_SCALE + capturedPieces.p * 2.5 * PIECE_SCALE - }rem`, - width: `${0.6 * PIECE_SCALE + capturedPieces.p * 0.7 * PIECE_SCALE}rem`, - height: `${1.7 * PIECE_SCALE}rem`, - }); - } - - if (capturedPieces.b) { - cssProps.push({ - backgroundPosition: `-${6.7 * PIECE_SCALE}rem ${ - -5.1 * PIECE_SCALE + capturedPieces.b * 2.6 * PIECE_SCALE - }rem`, - width: `${0.7 * PIECE_SCALE + capturedPieces.b * 0.8 * PIECE_SCALE}rem`, - height: `${ - 1.7 * PIECE_SCALE + capturedPieces.b * 0.1 * PIECE_SCALE - }rem`, - }); - } - - if (capturedPieces.n) { - cssProps.push({ - backgroundPosition: `-${9.5 * PIECE_SCALE}rem ${ - -4.9 * PIECE_SCALE + capturedPieces.n * 2.5 * PIECE_SCALE - }rem`, - width: `${0.9 * PIECE_SCALE + capturedPieces.n * 0.7 * PIECE_SCALE}rem`, - height: `${1.9 * PIECE_SCALE}rem`, - }); - } - - if (capturedPieces.r) { - cssProps.push({ - backgroundPosition: `${ - -12.2 * PIECE_SCALE + capturedPieces.r * 0.1 * PIECE_SCALE - }rem ${-5.1 * PIECE_SCALE + capturedPieces.r * 2.5 * PIECE_SCALE}rem`, - width: `${0.7 * PIECE_SCALE + capturedPieces.r * 0.8 * PIECE_SCALE}rem`, - height: `${1.7 * PIECE_SCALE}rem`, - }); - } - - if (capturedPieces.q) { - cssProps.push({ - backgroundPosition: `-${14.5 * PIECE_SCALE}rem ${0.1 * PIECE_SCALE}rem`, - width: `${1.8 * PIECE_SCALE}rem`, - height: `${1.9 * PIECE_SCALE}rem`, - }); - } - } - - return cssProps; + return ( + + {new Array(pieceCount).fill( + + )} + + ); }; diff --git a/src/lib/chess.ts b/src/lib/chess.ts index 4b9130a..15ca5f5 100644 --- a/src/lib/chess.ts +++ b/src/lib/chess.ts @@ -3,6 +3,7 @@ import { Game, Player } from "@/types/game"; import { Chess, PieceSymbol, Square } from "chess.js"; import { getPositionWinPercentage } from "./engine/helpers/winPercentage"; import { Color } from "@/types/enums"; +import { Piece } from "react-chessboard/dist/chessboard/types"; export const getEvaluateGameParams = (game: Chess): EvaluateGameParams => { const history = game.history({ verbose: true }); @@ -288,29 +289,56 @@ export const isCheck = (fen: string): boolean => { export const getCapturedPieces = ( fen: string, color: Color -): Record => { - const capturedPieces: Record = {}; - if (color === Color.White) { - capturedPieces.p = 8; - capturedPieces.r = 2; - capturedPieces.n = 2; - capturedPieces.b = 2; - capturedPieces.q = 1; - } else { - capturedPieces.P = 8; - capturedPieces.R = 2; - capturedPieces.N = 2; - capturedPieces.B = 2; - capturedPieces.Q = 1; - } +): { + piece: string; + count: number; +}[] => { + const capturedPieces = + color === Color.White + ? [ + { piece: "p", count: 8 }, + { piece: "b", count: 2 }, + { piece: "n", count: 2 }, + { piece: "r", count: 2 }, + { piece: "q", count: 1 }, + ] + : [ + { piece: "P", count: 8 }, + { piece: "B", count: 2 }, + { piece: "N", count: 2 }, + { piece: "R", count: 2 }, + { piece: "Q", count: 1 }, + ]; const fenPiecePlacement = fen.split(" ")[0]; - for (const piece of Object.keys(capturedPieces)) { - const count = fenPiecePlacement.match(new RegExp(piece, "g"))?.length; - if (count) capturedPieces[piece] = (capturedPieces[piece] ?? 0) - count; - } - return capturedPieces; + return capturedPieces.map(({ piece, count }) => { + const piecesLeftCount = fenPiecePlacement.match( + new RegExp(piece, "g") + )?.length; + const newPiece = pieceFenToSymbol[piece] ?? piece; + if (!count) return { piece: newPiece, count }; + + return { + piece: newPiece, + count: count - (piecesLeftCount ?? 0), + }; + }); +}; + +const pieceFenToSymbol: Record = { + p: "bP", + b: "bB", + n: "bN", + r: "bR", + q: "bQ", + k: "bK", + P: "wP", + B: "wB", + N: "wN", + R: "wR", + Q: "wQ", + K: "wK", }; export const getLineEvalLabel = ( diff --git a/src/sections/layout/index.tsx b/src/sections/layout/index.tsx index 87d5c2a..8cc0176 100644 --- a/src/sections/layout/index.tsx +++ b/src/sections/layout/index.tsx @@ -16,7 +16,7 @@ export default function Layout({ children }: PropsWithChildren) { main: red[400], }, primary: { - main: "#5d9948", + main: "#5a9943", }, secondary: { main: isDarkMode ? "#424242" : "#ffffff",