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 9caaad9..0000000
Binary files a/public/captured-pieces.png and /dev/null differ
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",