Initial version #1

Merged
drm merged 6 commits from dev into prod 2025-07-30 23:31:41 -04:00
15 changed files with 6816 additions and 1 deletions

8
Makefile Normal file
View File

@@ -0,0 +1,8 @@
SHELL := /bin/bash
build:
pnpm install
pnpm run build
start:
pnpm run start

View File

@@ -1,2 +1,32 @@
# games
# SolidStart
Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);
## Creating a project
```bash
# create a new project in the current directory
npm init solid@latest
# create a new project in my-app
npm init solid@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
Solid apps are built with _presets_, which optimise your project for deployment to different environments.
By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`.
## This project was created with the [Solid CLI](https://github.com/solidjs-community/solid-cli)

3
app.config.ts Normal file
View File

@@ -0,0 +1,3 @@
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({});

17
package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "games",
"type": "module",
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start"
},
"dependencies": {
"@solidjs/start": "^1.1.0",
"solid-js": "^1.9.5",
"vinxi": "^0.5.7"
},
"engines": {
"node": ">=22"
}
}

6588
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

0
src/app.css Normal file
View File

22
src/app.tsx Normal file
View File

@@ -0,0 +1,22 @@
import { createSignal } from "solid-js";
import "./app.css";
export default function App() {
const [count, setCount] = createSignal(0);
return (
<main>
<h1>Hello world!</h1>
<button class="increment" onClick={() => setCount(count() + 1)} type="button">
Clicks: {count()}
</button>
<p>
Visit{" "}
<a href="https://start.solidjs.com" target="_blank">
start.solidjs.com
</a>{" "}
to learn how to build SolidStart apps.
</p>
</main>
);
}

11
src/cards.ts Normal file
View File

@@ -0,0 +1,11 @@
export type Suit = "hearts" | "diamonds" | "spades" | "clubs";
export type Card = {
suit: Suit;
value: number;
};
export type Pile = Card[];
export type Stack = Card[];
export type Hand = Card[];
export type Board = Card[];

4
src/entry-client.tsx Normal file
View File

@@ -0,0 +1,4 @@
// @refresh reload
import { mount, StartClient } from "@solidjs/start/client";
mount(() => <StartClient />, document.getElementById("app")!);

21
src/entry-server.tsx Normal file
View File

@@ -0,0 +1,21 @@
// @refresh reload
import { createHandler, StartServer } from "@solidjs/start/server";
export default createHandler(() => (
<StartServer
document={({ assets, children, scripts }) => (
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
{assets}
</head>
<body>
<div id="app">{children}</div>
{scripts}
</body>
</html>
)}
/>
));

9
src/fn.ts Normal file
View 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
src/global.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="@solidjs/start/env" />

82
src/renaissance.ts Normal file
View File

@@ -0,0 +1,82 @@
import { Board, Card, Hand, Pile, Stack, Suit } from "./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" };
};

19
tsconfig.json Normal file
View File

@@ -0,0 +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/*"]
}
}
}