basic shape
This commit is contained in:
11
packages/client/index.html
Normal file
11
packages/client/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<script type="module" src="/src/entry-client.tsx"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" />
|
||||
</body>
|
||||
</html>
|
||||
17
packages/client/package.json
Normal file
17
packages/client/package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "client",
|
||||
"type": "module",
|
||||
"version": "0.0.2",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solidjs/router": "^0.15.3",
|
||||
"solid-js": "^1.9.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-solid": "^2.11.8"
|
||||
}
|
||||
}
|
||||
BIN
packages/client/public/favicon.ico
Normal file
BIN
packages/client/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
1
packages/client/public/views/back.svg
Symbolic link
1
packages/client/public/views/back.svg
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../assets/sources/Card_back_01.svg
|
||||
1
packages/client/public/views/cards
Symbolic link
1
packages/client/public/views/cards
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../assets/sources/Vector-Cards-Version-3.2/FACES (BORDERED)/STANDARD BORDERED/Single Cards (One Per FIle)
|
||||
71
packages/client/src/app.css
Normal file
71
packages/client/src/app.css
Normal file
@@ -0,0 +1,71 @@
|
||||
html {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
|
||||
"Lucida Sans", Arial, sans-serif;
|
||||
color: white;
|
||||
height: 100%;
|
||||
}
|
||||
body::before {
|
||||
z-index: -1;
|
||||
content: "";
|
||||
font-size: 28px;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgb(18, 229, 113);
|
||||
}
|
||||
a:visited {
|
||||
color: rgb(23, 138, 125);
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
background: radial-gradient(rgb(24, 82, 65), rgb(1, 42, 16));
|
||||
}
|
||||
|
||||
.hand {
|
||||
background: radial-gradient(rgb(24, 70, 82), rgb(1, 42, 41));
|
||||
}
|
||||
|
||||
.full {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.free {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.fixed-br {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.clear {
|
||||
pointer-events: none;
|
||||
}
|
||||
35
packages/client/src/app.tsx
Normal file
35
packages/client/src/app.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import "./app.css";
|
||||
import { Route, Router } from "@solidjs/router";
|
||||
import { Suspense } from "solid-js";
|
||||
import pkg from "../package.json";
|
||||
|
||||
const Version = () => (
|
||||
<div class="full free clear">
|
||||
<span
|
||||
style={{
|
||||
margin: "5px",
|
||||
"font-size": "0.8rem",
|
||||
"font-family": "monospace",
|
||||
"pointer-events": "all",
|
||||
}}
|
||||
class="fixed-br"
|
||||
>
|
||||
v{pkg.version}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router
|
||||
root={(props) => (
|
||||
<>
|
||||
<Suspense>{props.children}</Suspense>
|
||||
<Version />
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<Route path="/" component={() => "tesingt"} />
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
45
packages/client/src/components/Card.tsx
Normal file
45
packages/client/src/components/Card.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Component, createResource, JSX, Suspense } from "solid-js";
|
||||
import { Card, newDeck } from "../types/cards";
|
||||
import { Clickable, Stylable } from "./toolbox";
|
||||
|
||||
const cardToSvgFilename = (card: Card) => {
|
||||
if (card.kind == "joker") {
|
||||
return `JOKER-${card.color == "black" ? "2" : "3"}`;
|
||||
}
|
||||
|
||||
const value =
|
||||
{ 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) => {
|
||||
return (
|
||||
<Suspense>
|
||||
<img
|
||||
onClick={props.onClick}
|
||||
draggable={false}
|
||||
class={props.class}
|
||||
style={{
|
||||
"border-radius": "5px",
|
||||
...props.style,
|
||||
}}
|
||||
width="100px"
|
||||
src={
|
||||
props.face == "down"
|
||||
? "/views/back.svg"
|
||||
: `/views/cards/${cardToSvgFilename(props.card)}.svg`
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
}) satisfies Component<
|
||||
{
|
||||
card: Card;
|
||||
face?: "up" | "down";
|
||||
} & Stylable &
|
||||
Clickable
|
||||
>;
|
||||
54
packages/client/src/components/Game.tsx
Normal file
54
packages/client/src/components/Game.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
Accessor,
|
||||
createContext,
|
||||
createResource,
|
||||
JSX,
|
||||
Show,
|
||||
Suspense,
|
||||
} from "solid-js";
|
||||
import Card from "./Card";
|
||||
import Hand from "./Hand";
|
||||
import Pile from "./Pile";
|
||||
import { GameState, newDeck, shuffle, Hand as THand } from "../types/cards";
|
||||
import { createStore, produce, SetStoreFunction, Store } from "solid-js/store";
|
||||
import { getGameState, updateGameState } from "../db/Instances";
|
||||
|
||||
export const GameContext = createContext<{
|
||||
gameState: Accessor<GameState | undefined>;
|
||||
setGameState: (state: GameState) => Promise<any>;
|
||||
}>();
|
||||
|
||||
export default (props: { instanceId: number }) => {
|
||||
const [gameState, { refetch }] = createResource(() =>
|
||||
getGameState(props.instanceId)
|
||||
);
|
||||
const setGameState = (state: GameState) =>
|
||||
updateGameState(props.instanceId, state).then(refetch);
|
||||
|
||||
return (
|
||||
<GameContext.Provider value={{ gameState, setGameState }}>
|
||||
<Show when={gameState() != undefined}>
|
||||
<div
|
||||
onClick={() => {}}
|
||||
class="full column center"
|
||||
style={{ "row-gap": "20px", "font-size": "32px" }}
|
||||
>
|
||||
<div class="full center">
|
||||
<Pile
|
||||
pile={gameState()!.deck}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
const [drawn, ...rest] = gameState()!.deck;
|
||||
setGameState({
|
||||
deck: rest,
|
||||
hand: [drawn, ...gameState()!.hand],
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Hand hand={gameState()!.hand} />
|
||||
</div>
|
||||
</Show>
|
||||
</GameContext.Provider>
|
||||
);
|
||||
};
|
||||
51
packages/client/src/components/Hand.tsx
Normal file
51
packages/client/src/components/Hand.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Component, For, useContext } from "solid-js";
|
||||
import Card from "./Card";
|
||||
import { Hand } from "../types/cards";
|
||||
import { GameContext } from "./Game";
|
||||
import { produce } from "solid-js/store";
|
||||
|
||||
export default ((props) => {
|
||||
const { setGameState, gameState } = useContext(GameContext)!;
|
||||
|
||||
return (
|
||||
<div
|
||||
class="hand"
|
||||
style={{
|
||||
"min-width": "100px",
|
||||
width: "fit-content",
|
||||
"max-width": "80%",
|
||||
border: "2px dashed white",
|
||||
"border-radius": "12px",
|
||||
margin: "10px",
|
||||
"margin-bottom": "25px",
|
||||
padding: "10px",
|
||||
height: "180px",
|
||||
overflow: "scroll",
|
||||
"scrollbar-width": "none",
|
||||
display: "flex",
|
||||
gap: "5px",
|
||||
}}
|
||||
>
|
||||
<For each={props.hand}>
|
||||
{(card) => (
|
||||
<Card
|
||||
card={card}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => {
|
||||
const index = gameState()!.hand.indexOf(card);
|
||||
setGameState({
|
||||
deck: [card, ...gameState()!.deck],
|
||||
hand: [
|
||||
...gameState()!.hand.slice(0, index),
|
||||
...gameState()!.hand.slice(index + 1),
|
||||
],
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
);
|
||||
}) satisfies Component<{ hand: Hand }>;
|
||||
46
packages/client/src/components/Pile.tsx
Normal file
46
packages/client/src/components/Pile.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Component, For, JSX } from "solid-js";
|
||||
import Card from "./Card";
|
||||
import { Pile } from "../types/cards";
|
||||
import { type ComponentProps } from "solid-js";
|
||||
import { Clickable, Stylable } from "./toolbox";
|
||||
|
||||
export default ((props) => {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
class={`center ${props.class ?? ""}}`.trim()}
|
||||
style={{
|
||||
width: "200px",
|
||||
height: "400px",
|
||||
...(props.style as JSX.CSSProperties),
|
||||
}}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<For each={props.pile}>
|
||||
{(card, i) => (
|
||||
<Card
|
||||
card={card}
|
||||
face="down"
|
||||
style={{
|
||||
position: "absolute",
|
||||
transform: `translate(${i() * 0.5}px, ${
|
||||
i() * 0.2
|
||||
}px)`,
|
||||
// "z-index": 100 - i(),
|
||||
border: `0.1px solid rgb(${
|
||||
10 + i() + Math.random() * 50
|
||||
}, ${10 + i() + Math.random() * 50}, ${
|
||||
10 + i() + Math.random() * 50
|
||||
});`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
);
|
||||
}) satisfies Component<
|
||||
{
|
||||
pile: Pile;
|
||||
} & Stylable &
|
||||
Clickable
|
||||
>;
|
||||
0
packages/client/src/components/Player.tsx
Normal file
0
packages/client/src/components/Player.tsx
Normal file
0
packages/client/src/components/Table.tsx
Normal file
0
packages/client/src/components/Table.tsx
Normal file
16
packages/client/src/components/toolbox.tsx
Normal file
16
packages/client/src/components/toolbox.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { JSX } from "solid-js";
|
||||
|
||||
export type Stylable = {
|
||||
class?: string;
|
||||
style?: JSX.CSSProperties;
|
||||
};
|
||||
|
||||
export type Clickable = {
|
||||
onClick?:
|
||||
| JSX.EventHandlerUnion<
|
||||
HTMLDivElement,
|
||||
MouseEvent,
|
||||
JSX.EventHandler<HTMLDivElement, MouseEvent>
|
||||
>
|
||||
| undefined;
|
||||
};
|
||||
4
packages/client/src/db/Games.ts
Normal file
4
packages/client/src/db/Games.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
"use server";
|
||||
import { prisma } from "./db";
|
||||
|
||||
export const queryAll = async () => await prisma.game.findMany();
|
||||
25
packages/client/src/db/Instances.ts
Normal file
25
packages/client/src/db/Instances.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
"use server";
|
||||
|
||||
import { GameState, newDeck, shuffle } from "../types/cards";
|
||||
import { prisma } from "./db";
|
||||
|
||||
export const queryInstances = async (gameName: string) =>
|
||||
prisma.instance.findMany({ where: { game: { name: gameName } } });
|
||||
|
||||
export const createInstance = (gameName: string) =>
|
||||
prisma.instance.create({
|
||||
data: {
|
||||
gameState: { deck: shuffle(newDeck()), hand: [] } as GameState,
|
||||
game: { connect: { name: gameName } },
|
||||
},
|
||||
});
|
||||
|
||||
export const getGameState = (instanceId: number) =>
|
||||
prisma.instance
|
||||
.findUnique({ where: { id: instanceId } })
|
||||
.then((i) => i?.gameState as GameState | undefined);
|
||||
|
||||
export const updateGameState = async (
|
||||
instanceId: number,
|
||||
gameState: GameState
|
||||
) => prisma.instance.update({ where: { id: instanceId }, data: { gameState } });
|
||||
5
packages/client/src/db/db.ts
Normal file
5
packages/client/src/db/db.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
"use server";
|
||||
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
export const prisma = new PrismaClient();
|
||||
4
packages/client/src/entry-client.tsx
Normal file
4
packages/client/src/entry-client.tsx
Normal file
@@ -0,0 +1,4 @@
|
||||
import App from "./app";
|
||||
import { render } from "solid-js/web";
|
||||
|
||||
render(App, document.getElementById("app")!);
|
||||
9
packages/client/src/fn.ts
Normal file
9
packages/client/src/fn.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
declare global {
|
||||
interface Array<T> {
|
||||
thru<S>(fn: (arr: T[]) => S): S;
|
||||
}
|
||||
}
|
||||
Array.prototype.thru = function <T, S>(this: T[], fn: (arr: T[]) => S) {
|
||||
return fn(this);
|
||||
};
|
||||
export const clone = <T>(o: T): T => JSON.parse(JSON.stringify(o));
|
||||
1
packages/client/src/global.d.ts
vendored
Normal file
1
packages/client/src/global.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="@solidjs/start/env" />
|
||||
82
packages/client/src/renaissance.ts
Normal file
82
packages/client/src/renaissance.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Board, Card, Hand, Pile, Stack, Suit } from "./types/cards";
|
||||
import { clone } from "./fn";
|
||||
|
||||
const AGG: Suit = "spades";
|
||||
const CUL: Suit = "hearts";
|
||||
const TECH: Suit = "diamonds";
|
||||
const MIL: Suit = "clubs";
|
||||
|
||||
type GameState = {
|
||||
mainPile: Pile;
|
||||
discardStack: Stack;
|
||||
deadPile: Pile;
|
||||
players: {
|
||||
hand: Hand;
|
||||
board: Board;
|
||||
}[];
|
||||
playerTurn: number;
|
||||
lastMove: Move;
|
||||
prevState: GameState | null;
|
||||
};
|
||||
|
||||
type Move =
|
||||
| {
|
||||
type: "draw";
|
||||
fromPile: "main" | "discard";
|
||||
}
|
||||
| { type: "play"; card: Card }
|
||||
| { type: "remove"; card: Card }
|
||||
| { type: "attack"; army: Card[] }
|
||||
| { type: "pass" };
|
||||
|
||||
type Action = Move | { type: "discard"; cards: Card[] };
|
||||
|
||||
const techTier = (techValue: number) => Math.ceil(techValue / 14);
|
||||
const moveCost = (move: Move) => (move.type == "attack" ? move.army.length : 1);
|
||||
const movesSpent = (state: GameState): number =>
|
||||
state.playerTurn != state.prevState?.playerTurn
|
||||
? 0
|
||||
: moveCost(state.lastMove) + movesSpent(state.prevState);
|
||||
|
||||
const value = (suit: Suit) => (board: Board) =>
|
||||
board
|
||||
.filter((card) => card.suit === suit)
|
||||
.reduce((v, card) => v + card.value, 0);
|
||||
|
||||
export const getNextState = (p: {
|
||||
state: GameState;
|
||||
move: Move;
|
||||
}): GameState | { illegal: string } => {
|
||||
const { state, move } = p;
|
||||
|
||||
const currentPlayer = state.players[state.playerTurn];
|
||||
|
||||
const population = currentPlayer.board.thru(value(AGG));
|
||||
const culture = currentPlayer.board.thru(value(CUL));
|
||||
const tech = techTier(currentPlayer.board.thru(value(TECH)));
|
||||
|
||||
const movesRemaining = tech - movesSpent(state);
|
||||
|
||||
const newState = clone(state);
|
||||
if (move.type === "draw") {
|
||||
const pile =
|
||||
move.fromPile === "main"
|
||||
? newState.mainPile
|
||||
: newState.discardStack;
|
||||
|
||||
if (pile.length === 0) {
|
||||
return {
|
||||
illegal: `The ${move.fromPile} pile is empty; cannot draw`,
|
||||
};
|
||||
}
|
||||
|
||||
newState.players[newState.playerTurn].hand.push(pile.pop()!);
|
||||
if (movesRemaining == 1) {
|
||||
newState.playerTurn =
|
||||
(newState.playerTurn + 1) % newState.players.length;
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
return { illegal: "idk bruh" };
|
||||
};
|
||||
30
packages/client/src/routes/[game]/[instance].tsx
Normal file
30
packages/client/src/routes/[game]/[instance].tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { A, useParams } from "@solidjs/router";
|
||||
|
||||
import { createEffect, createResource, Show, Suspense } from "solid-js";
|
||||
import Game from "../../components/Game";
|
||||
import { getGameState } from "../../db/Instances";
|
||||
|
||||
export default () => {
|
||||
const params = useParams<{ game: string; instance: string }>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Game instanceId={Number.parseInt(params.instance)} />
|
||||
<A
|
||||
href={`/${params.game}`}
|
||||
style={{
|
||||
position: "absolute",
|
||||
padding: "10px",
|
||||
top: "0",
|
||||
left: "0",
|
||||
margin: "20px",
|
||||
"background-color": "white",
|
||||
"border-radius": "8px",
|
||||
border: "2px solid black",
|
||||
}}
|
||||
>
|
||||
Back
|
||||
</A>
|
||||
</>
|
||||
);
|
||||
};
|
||||
39
packages/client/src/routes/[game]/index.tsx
Normal file
39
packages/client/src/routes/[game]/index.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { A, useParams } from "@solidjs/router";
|
||||
|
||||
import { createEffect, createResource, For, Suspense } from "solid-js";
|
||||
import * as Instance from "../../db/Instances";
|
||||
|
||||
export default () => {
|
||||
const params = useParams<{ game: string }>();
|
||||
|
||||
const [instances, { refetch }] = createResource(
|
||||
() => params.game,
|
||||
() => Instance.queryInstances(params.game)
|
||||
);
|
||||
|
||||
return (
|
||||
<Suspense>
|
||||
<div style={{ padding: "20px" }}>
|
||||
<h1 style={{ margin: 0 }}>{params.game}</h1>
|
||||
<button
|
||||
onClick={() =>
|
||||
Instance.createInstance(params.game).then(refetch)
|
||||
}
|
||||
>
|
||||
New Game
|
||||
</button>
|
||||
<ul>
|
||||
<For each={instances() ?? []}>
|
||||
{(instance) => (
|
||||
<li>
|
||||
<A href={`/${params.game}/${instance.id}`}>
|
||||
{instance.id}
|
||||
</A>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
</div>
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
14
packages/client/src/routes/index.tsx
Normal file
14
packages/client/src/routes/index.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { A } from "@solidjs/router";
|
||||
import { createResource, For } from "solid-js";
|
||||
import * as Games from "../db/Games";
|
||||
|
||||
export default () => {
|
||||
const [games] = createResource(() => Games.queryAll());
|
||||
return (
|
||||
<div style={{ padding: "20px" }}>
|
||||
<For each={games()}>
|
||||
{(game) => <A href={`/${game.name}`}>{game.name}</A>}
|
||||
</For>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
67
packages/client/src/types/cards.ts
Normal file
67
packages/client/src/types/cards.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
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];
|
||||
|
||||
export type Card =
|
||||
| {
|
||||
kind: "normal";
|
||||
suit: Suit;
|
||||
rank: Rank;
|
||||
}
|
||||
| { kind: "joker"; color: "red" | "black" };
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
export type GameState = {
|
||||
deck: Pile;
|
||||
hand: Hand;
|
||||
};
|
||||
export const newGame = () =>
|
||||
({
|
||||
deck: shuffle(newDeck()),
|
||||
hand: [],
|
||||
} as GameState);
|
||||
20
packages/client/tsconfig.json
Normal file
20
packages/client/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"],
|
||||
"$/*": ["./"],
|
||||
"@/*": ["./public/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
6
packages/client/vite.config.ts
Normal file
6
packages/client/vite.config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { defineConfig } from "vite";
|
||||
import solidPlugin from "vite-plugin-solid";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solidPlugin()],
|
||||
});
|
||||
Reference in New Issue
Block a user