diff --git a/assets/sources/Card_back_01.svg b/assets/sources/Card_back_01.svg new file mode 100644 index 0000000..33c9ab1 --- /dev/null +++ b/assets/sources/Card_back_01.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2780e41eb510b73fd3238f5e3328908aaff1a19b8b1e52ec30998d51b56be50 +size 123591 diff --git a/assets/views/back.svg b/assets/views/back.svg new file mode 120000 index 0000000..3ea4d28 --- /dev/null +++ b/assets/views/back.svg @@ -0,0 +1 @@ +../sources/Card_back_01.svg \ No newline at end of file diff --git a/src/app.css b/src/app.css index 3f1f248..54cbea7 100644 --- a/src/app.css +++ b/src/app.css @@ -28,6 +28,10 @@ body::before { width: 100%; } +.w-full { + width: 100%; +} + .center { display: flex; justify-content: center; diff --git a/src/components/Card.tsx b/src/components/Card.tsx index a75b487..3a2cd88 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -1,4 +1,4 @@ -import { Component, createResource, Suspense } from "solid-js"; +import { Component, createResource, JSX, Suspense } from "solid-js"; import { Card } from "../types/cards"; const cardToSvgFilename = (card: Card) => { @@ -7,24 +7,43 @@ const cardToSvgFilename = (card: Card) => { } const value = - { ace: 1, jack: 11, queen: 12, king: 13 }[card.rank] ?? - (card.rank as number); + { ace: 1, jack: 11, queen: 12, king: 13 }[ + card.rank as "ace" | "jack" | "queen" | "king" // fuck you typescript + ] ?? (card.rank as number); return `${card.suit.toUpperCase()}-${value}${ value >= 11 ? "-" + (card.rank as string).toUpperCase() : "" }`; }; export default ((props) => { - const [svgPath] = createResource( - () => - import( - `~/../assets/views/cards/${cardToSvgFilename(props.card)}.svg` - ) + const [svgPath] = createResource(() => + props.face == "down" + ? // @ts-ignore + import("~/../assets/views/back.svg") + : import( + `~/../assets/views/cards/${cardToSvgFilename( + props.card + )}.svg` + ) ); return ( - + ); -}) satisfies Component<{ card: Card }>; +}) satisfies Component<{ + class?: string; + style?: JSX.CSSProperties; + card: Card; + face?: "up" | "down"; +}>; diff --git a/src/components/Game.tsx b/src/components/Game.tsx index 0973c15..1dc4720 100644 --- a/src/components/Game.tsx +++ b/src/components/Game.tsx @@ -1,15 +1,40 @@ -import { JSX } from "solid-js"; +import { createContext, JSX } from "solid-js"; import Card from "./Card"; +import Hand from "./Hand"; +import Pile from "./Pile"; +import { newDeck, shuffle, Hand as THand } from "../types/cards"; +import { createStore, produce } from "solid-js/store"; + +const GameContext = createContext(); export default () => { + const [gameState, setGameState] = createStore({ + pile: shuffle(newDeck()), + hand: [] as THand, + }); + return ( -
- games - - coming soon -
+ +
{}} + class="full column" + style={{ "row-gap": "20px", "font-size": "32px" }} + > +
+ + setGameState( + produce((state) => { + state.hand.push(state.pile.pop()!); + }) + ) + } + /> +
+ +
+
); }; diff --git a/src/components/Hand.tsx b/src/components/Hand.tsx index e69de29..8277be1 100644 --- a/src/components/Hand.tsx +++ b/src/components/Hand.tsx @@ -0,0 +1,24 @@ +import { Component, For } from "solid-js"; +import Card from "./Card"; +import { Hand } from "../types/cards"; + +export default ((props) => { + return ( +
+ {(card) => } +
+ ); +}) satisfies Component<{ hand: Hand }>; diff --git a/src/components/Pile.tsx b/src/components/Pile.tsx index e69de29..f8b3c2d 100644 --- a/src/components/Pile.tsx +++ b/src/components/Pile.tsx @@ -0,0 +1,44 @@ +import { Component, For, JSX } from "solid-js"; +import Card from "./Card"; +import { Pile } from "../types/cards"; + +export default ((props) => { + return ( +
+ + {(card, i) => ( + + )} + +
+ ); +}) satisfies Component<{ + pile: Pile; + style?: JSX.CSSProperties; + onClick?: + | JSX.EventHandlerUnion< + HTMLDivElement, + MouseEvent, + JSX.EventHandler + > + | undefined; +}>; diff --git a/src/types/cards.ts b/src/types/cards.ts index 94f5970..029680d 100644 --- a/src/types/cards.ts +++ b/src/types/cards.ts @@ -1,6 +1,23 @@ -export type Suit = "heart" | "diamond" | "spade" | "club"; +const suits = ["heart", "diamond", "spade", "club"] as const; +export type Suit = (typeof suits)[number]; + +const ranks = [ + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + "jack", + "queen", + "king", + "ace", +] as const; +export type Rank = (typeof ranks)[number]; -type Rank = number | "jack" | "queen" | "king" | "ace"; export type Card = | { kind: "normal"; @@ -13,3 +30,28 @@ export type Pile = Card[]; export type Stack = Card[]; export type Hand = Card[]; export type Board = Card[]; + +export const newDeck = (withJokers = false): Pile => + suits + .map((suit) => + ranks.map((rank) => ({ kind: "normal", suit, rank } as Card)) + ) + .flat() + .concat( + withJokers + ? [ + { kind: "joker", color: "red" }, + { kind: "joker", color: "black" }, + ] + : [] + ); + +export const shuffle = (cards: Card[]) => { + let i = cards.length; + while (i > 0) { + const j = Math.floor(Math.random() * i); + i--; + [cards[i], cards[j]] = [cards[j], cards[i]]; + } + return cards; +}; diff --git a/tsconfig.json b/tsconfig.json index 7d5871a..3a1138c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,19 @@ { - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - "allowJs": true, - "strict": true, - "noEmit": true, - "types": ["vinxi/types/client"], - "isolatedModules": true, - "paths": { - "~/*": ["./src/*"] - } - } + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "allowJs": true, + "strict": true, + "noEmit": true, + "types": ["vinxi/types/client"], + "isolatedModules": true, + "paths": { + "~/*": ["./src/*"] + } + } }