diff --git a/packages/client/src/components/Card.tsx b/packages/client/src/components/Card.tsx index a841a10..780e1dc 100644 --- a/packages/client/src/components/Card.tsx +++ b/packages/client/src/components/Card.tsx @@ -1,6 +1,7 @@ import { Component, createResource, JSX, Suspense } from "solid-js"; -import { Card, newDeck } from "../types/cards"; + import { Clickable, Stylable } from "./toolbox"; +import { Card } from "../../../shared/cards"; const cardToSvgFilename = (card: Card) => { if (card.kind == "joker") { @@ -37,9 +38,13 @@ export default ((props) => { ); }) satisfies Component< - { - card: Card; - face?: "up" | "down"; - } & Stylable & + ( + | { + card: Card; + face?: "up"; + } + | { card?: Card; face: "down" } + ) & + Stylable & Clickable >; diff --git a/packages/client/src/components/Game.tsx b/packages/client/src/components/Game.tsx index da7c25f..dd63a12 100644 --- a/packages/client/src/components/Game.tsx +++ b/packages/client/src/components/Game.tsx @@ -3,46 +3,45 @@ import { GameState, Action, vGameState, + PlayerView, } from "../../../server/src/games/simple"; import api from "../api"; import Hand from "./Hand"; import Pile from "./Pile"; export const GameContext = createContext<{ - gameState: Accessor; + view: Accessor; submitAction: (action: Action) => Promise; }>(); export default (props: { instanceId: string }) => { - const [gameState, { mutate }] = createResource(() => + const [view, { mutate }] = createResource(() => api .simple(props) .get() - .then((res) => res.data as GameState) + .then((res) => res.data as PlayerView) ); const submitAction = (action: Action) => api .simple(props) .post({ action }) - .then((res) => res.status == 200 && mutate(res.data as vGameState)); + .then((res) => res.status == 200 && mutate(res.data as PlayerView)); return ( - - + +
- api.simple({ instanceId: props.instanceId }) - } + onClick={() => submitAction({ type: "draw" })} />
- +
diff --git a/packages/client/src/components/Hand.tsx b/packages/client/src/components/Hand.tsx index 90c9b96..38e1aaf 100644 --- a/packages/client/src/components/Hand.tsx +++ b/packages/client/src/components/Hand.tsx @@ -5,7 +5,7 @@ import { GameContext } from "./Game"; import { produce } from "solid-js/store"; export default ((props) => { - const { submitAction, gameState } = useContext(GameContext)!; + const { submitAction, view } = useContext(GameContext)!; return (
{ @@ -16,31 +15,14 @@ export default ((props) => { }} onClick={props.onClick} > - - {(card, i) => ( - - )} - + 0}> + +
); }) satisfies Component< { - pile: Pile; + count: number; } & Stylable & Clickable >; diff --git a/packages/server/src/games/simple.ts b/packages/server/src/games/simple.ts index 1c4d90a..4ce2bbb 100644 --- a/packages/server/src/games/simple.ts +++ b/packages/server/src/games/simple.ts @@ -47,7 +47,10 @@ export const newGame = (players: string[]) => { } as GameState; }; -export const getKnowledge = (state: GameState, humanId: string) => ({ +export const getKnowledge = ( + state: GameState, + humanId: string +): vGameState => ({ humanId, deck: state.deck.map((_) => null), players: Object.fromEntries( @@ -58,6 +61,17 @@ export const getKnowledge = (state: GameState, humanId: string) => ({ ), }); +const getView = (state: vGameState, humanId: string): PlayerView => ({ + humanId, + deckCount: state.deck.length, + myHand: state.players[humanId] as Hand, + playerHandCounts: Object.fromEntries( + Object.entries(state.players) + .filter(([id]) => id != humanId) + .map(([id, hand]) => [id, hand.length]) + ), +}); + export const resolveAction = ( state: GameState, humanId: string, @@ -112,21 +126,31 @@ export const simpleApi = new Elysia({ prefix: "/simple" }) ) .group("/:instanceId", (app) => app - .get("/", ({ params: { instanceId } }) => - prisma.instance - .findUnique({ - where: { - id: instanceId, - }, - }) - .then((game) => game?.gameState) + .get( + "/", + ({ params: { instanceId }, headers: { human: humanId } }) => + prisma.instance + .findUnique({ + where: { + id: instanceId, + }, + }) + .then((game) => + getView( + getKnowledge( + game!.gameState as GameState, + humanId! + ), + humanId! + ) + ) ) .post( "/", ({ params: { instanceId }, body: { action }, - headers: { Human: humanId }, + headers: { human: humanId }, }) => prisma.instance .findUniqueOrThrow({ @@ -134,20 +158,22 @@ export const simpleApi = new Elysia({ prefix: "/simple" }) id: instanceId, }, }) - .then((game) => { + .then(async (game) => { const newState = resolveAction( game.gameState as GameState, humanId!, action ); - const knownState = getKnowledge(newState, humanId!); - void prisma.instance.update({ + await prisma.instance.update({ data: { gameState: newState }, where: { id: instanceId, }, }); - return knownState; + return getView( + getKnowledge(newState, humanId!), + humanId! + ); }), { body: t.Object({