feat: add local game and history

This commit is contained in:
Cozma Rares
2023-08-02 01:38:08 +03:00
parent 69cd39f5e3
commit 02333e68cd
8 changed files with 163 additions and 35 deletions
+2 -2
View File
@@ -114,9 +114,9 @@ const ChessBoard: React.FC<{
return (
<>
<div className="relative w-fit h-fit isolate border-[6px] border-black rounded-lg peer">
<div className="relative w-fit h-fit max-w-full isolate border-[6px] border-black rounded-lg peer">
<div
className="grid grid-rows-8 grid-cols-8 aspect-square select-none"
className="grid grid-rows-8 grid-cols-8 aspect-square select-none max-w-full"
onClick={handleClick}
style={{ width: `${gridSize}px` }}
>
+6
View File
@@ -1,7 +1,13 @@
@import url("https://fonts.googleapis.com/css2?family=Ubuntu+Mono&display=swap");
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: "Ubuntu Mono", monospace;
}
img {
max-width: 100%;
max-height: 100%;
+10 -5
View File
@@ -6,7 +6,8 @@ import {
useNavigate,
} from "react-router-dom";
import Home from "./routes/Home";
import Game from "./routes/Game";
import OnlineGame from "./routes/OnlineGame";
import LocalGame from "./routes/LocalGame";
import { useEffect } from "react";
const ErrorElement = () => {
@@ -14,7 +15,7 @@ const ErrorElement = () => {
useEffect(() => naviagte("/"), []);
return <></>;
return <h1 className="text-2xl bold loading">Redirecting to home page</h1>;
};
const router = createBrowserRouter([
@@ -23,8 +24,12 @@ const router = createBrowserRouter([
element: <Home />,
},
{
path: "/game",
element: <Game />,
path: "/game/online",
element: <OnlineGame />,
},
{
path: "/game/local",
element: <LocalGame />,
},
{
path: "*",
@@ -35,7 +40,7 @@ const router = createBrowserRouter([
// TODO: better UI
// React's StricMode doesn't play well with how I implemented the socket connection
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<div className="absolute top-0 left-0 right-0 bottom-0 w-full h-full bg-zinc-200 -z-10">
<div className="absolute top-0 left-0 right-0 bottom-0 w-full h-full bg-zinc-600 -z-100">
<RouterProvider router={router} />
</div>
);
+14 -17
View File
@@ -25,7 +25,7 @@ const Home = () => {
throw res;
})
.then((text) => {
navigate("/game", { state: { id: text, color } });
navigate("/game/online", { state: { id: text, color } });
})
.catch((err) => {
console.error(err);
@@ -43,7 +43,7 @@ const Home = () => {
if (text == "invalid id") throw new Error("Invalid game ID");
if (text == "full") throw new Error("Game already has 2 players");
navigate("/game", { state: { id, color: text } });
navigate("/game/online", { state: { id, color: text } });
})
.catch((err) => {
console.error(err);
@@ -70,11 +70,16 @@ const Home = () => {
<>
<ErrorNorification key={errObj.error} {...errObj} />
<div className="text-xl">
<div className="absolute top-0 left-0 right-0 bottom-0 m-auto w-fit h-fit">
<Modal>
<ModalButton onClick={() => setCreate(true)}>Create Game</ModalButton>
<ModalButton onClick={() => setJoin(true)}>Join Game</ModalButton>
</Modal>
<div className="absolute top-0 left-0 right-0 bottom-0 m-auto w-fit h-fit">
<Modal>
<ModalButton onClick={() => setCreate(true)}>
Create Game
</ModalButton>
<ModalButton onClick={() => setJoin(true)}>Join Game</ModalButton>
<ModalButton onClick={() => navigate("/game/local")}>
Play locally
</ModalButton>
</Modal>
</div>
<Show when={create}>
<Modal enableOverlay>
@@ -102,16 +107,8 @@ const Home = () => {
<label htmlFor="black">Black</label>
</div>
</div>
<ModalButton
onClick={createGame}
>
Start Game
</ModalButton>
<ModalButton
onClick={() => setCreate(false)}
>
Cancel
</ModalButton>
<ModalButton onClick={createGame}>Start Game</ModalButton>
<ModalButton onClick={() => setCreate(false)}>Cancel</ModalButton>
</div>
</Modal>
</Show>
+77
View File
@@ -0,0 +1,77 @@
import { ReactNode, useState } from "react";
import Chess, { Move } from "../../../server/src/engine";
import ChessBoard from "../components/Chessboard";
import { CaretRight, Plus, Repeat } from "../utils/icons";
const LocalGame = () => {
const [chess] = useState(Chess.load());
const [, rerender] = useState(false);
const makeMove = (move: Move) => {
chess.makeMove(move);
rerender((prev) => !prev);
};
const history: ReactNode[] = new Array((chess.getHistory().length + 1) >> 1);
const chessHistory = chess.getHistory();
let idx = 0;
for (let i = 1; i < chessHistory.length; i += 2)
history[idx++] = (
<div key={idx} className="flex flex-row gap-4">
<span>{idx}.</span>
<span>{chessHistory[i - 1].san}</span>
<span>{chessHistory[i].san}</span>
</div>
);
if (chessHistory.length % 2)
history[idx++] = (
<div key={idx} className="flex flex-row gap-4">
<span>{idx}.</span>
<span>{chessHistory.at(-1)?.san}</span>
<span className="w-1"></span>
</div>
);
return (
<div className="mt-4 flex flex-row gap-4 justify-center">
<ChessBoard chess={chess} makeMove={makeMove} />
<div className="text-white grid grid-rows-[1fr,auto]">
<div className="bg-zinc-800 p-4 rounded-t-lg">{history}</div>
<div className="bg-black grid grid-cols-4 gap-5 p-4 rounded-b-lg">
{/* TODO: */}
<Button>
<Plus />
</Button>
<Button>
<Repeat />
</Button>
<Button className="rotate-180">
<CaretRight />
</Button>
<Button>
<CaretRight />
</Button>
</div>
</div>
</div>
);
};
const Button: React.FC<{ children: React.ReactNode; className?: string }> = ({
children,
className,
}) => (
<button
className={
"min-w-[1rem] mt-auto bg-zinc-800 flex justify-center items-center p-2 rounded-md " +
(className ?? "")
}
>
{children}
</button>
);
export default LocalGame;
+39
View File
@@ -26,3 +26,42 @@ export const CircleExclamation = () => (
<path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-384c13.3 0 24 10.7 24 24V264c0 13.3-10.7 24-24 24s-24-10.7-24-24V152c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z" />
</svg>
);
// Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc.
export const CaretRight = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
stroke="currentColor"
fill="currentColor"
viewBox="0 0 320 512"
height="1em"
>
<path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z" />
</svg>
);
// Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc.
export const Repeat = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
stroke="currentColor"
fill="currentColor"
height="1em"
width="1em"
>
<path d="M0 224c0 17.7 14.3 32 32 32s32-14.3 32-32c0-53 43-96 96-96H320v32c0 12.9 7.8 24.6 19.8 29.6s25.7 2.2 34.9-6.9l64-64c12.5-12.5 12.5-32.8 0-45.3l-64-64c-9.2-9.2-22.9-11.9-34.9-6.9S320 19.1 320 32V64H160C71.6 64 0 135.6 0 224zm512 64c0-17.7-14.3-32-32-32s-32 14.3-32 32c0 53-43 96-96 96H192V352c0-12.9-7.8-24.6-19.8-29.6s-25.7-2.2-34.9 6.9l-64 64c-12.5 12.5-12.5 32.8 0 45.3l64 64c9.2 9.2 22.9 11.9 34.9 6.9s19.8-16.6 19.8-29.6V448H352c88.4 0 160-71.6 160-160z" />
</svg>
);
// Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc.
export const Plus = () => (
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
stroke="currentColor"
fill="currentColor"
height="1em"
>
<path d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H48c-17.7 0-32 14.3-32 32s14.3 32 32 32H192V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H400c17.7 0 32-14.3 32-32s-14.3-32-32-32H256V80z" />
</svg>
);