diff --git a/src/pages/ants/index.tsx b/src/pages/ants/index.tsx
index 04e093c..8664341 100644
--- a/src/pages/ants/index.tsx
+++ b/src/pages/ants/index.tsx
@@ -7,6 +7,7 @@ import { useEffect, useRef, useState } from "react"
export const meta: RouteMeta = {
title: 'Ants',
+ image: './screen.png'
}
export default function () {
@@ -45,9 +46,9 @@ export default function () {
ant: [0xcc, 0xcc, 0xcc, 0xff],
antAndFood: [0xee, 0x44, 0xee, 0xff],
food: [0, 0x80, 0, 0xff],
- pheromoneToFood: [0x20, 0xff, 0x20, 0xff],
+ pheromoneToFood: [0x20, 0xee, 0x20, 0xff],
pheromoneToHill: [0xa0, 0x20, 0x20, 0x80],
- pheromoneBoth: [0x70, 0xff, 0x20, 0xff],
+ pheromoneBoth: [0xa0, 0xee, 0x20, 0xff],
anthill: [0x80, 0, 0, 0xff],
void: [0, 0, 0, 0xff],
}
diff --git a/src/pages/ants/screen.png b/src/pages/ants/screen.png
new file mode 100644
index 0000000..a093d68
Binary files /dev/null and b/src/pages/ants/screen.png differ
diff --git a/src/pages/artisan-td-calc/index.tsx b/src/pages/artisan-td-calc/index.tsx
deleted file mode 100644
index 9b546bf..0000000
--- a/src/pages/artisan-td-calc/index.tsx
+++ /dev/null
@@ -1,329 +0,0 @@
-import { useMemo, useState, type CSSProperties } from "react"
-import styles from './styles.module.css'
-import { Head } from "~/components/Head"
-import type { RouteMeta } from "~/router"
-
-export const meta: RouteMeta = {
- title: 'Artisan TD calculator',
-}
-
-const SIDE = 8
-const TURNS = 15
-
-enum State {
- OFF,
- ON,
- INSIDE,
-}
-
-const makeGrid = (value: State = State.OFF) => Array.from({ length: SIDE }, () => Array.from({ length: SIDE }, () => value))
-
-export default function Lightning() {
- const [grid, setGrid] = useState(makeGrid)
-
- const computed = useMemo(() => computeInside(grid), [grid])
-
-
- return (
-
-
-
- Click on the grid below to draw your farm towers:
- {
- const newGrid = structuredClone(grid)
- newGrid[y][x] = value
- setGrid(newGrid)
- }}
- />
-
-
- )
-}
-
-function Results({ grid }: { grid: State[][] }) {
- const summary = useMemo(() => counts(grid), [grid])
-
- const cost = summary[State.ON] * 20
- const perTurn = summary[State.INSIDE] * 10
-
- const rows = {
- total: Array.from({ length: TURNS }, (_, i) => Math.round(perTurn * (i + 1) - cost)),
- totalSell: Array.from({ length: TURNS }, (_, i) => Math.round(perTurn * (i + 1) - cost / 2)),
- bank: Array.from({ length: TURNS }, (_, i) => Math.round(i * cost * 0.2)),
- bankCompound: Array.from({ length: TURNS }, (_, i) => Math.round(cost * 1.2 ** i - cost)),
- both: Array.from({ length: TURNS }).reduce((arr, _, i) => (arr.push(Math.round((i === 0 ? 0 : ((arr[i - 1] + cost / 2) * 1.2)) + perTurn - cost / 2)), arr), []),
- } as const
-
- return (
- <>
-
-
-
- Initial cost |
- {cost} |
-
-
- Sale price |
- {cost / 2} |
-
-
- Per turn |
- {perTurn} |
-
-
- Walls |
- {summary[State.ON]} |
-
-
- Fields |
- {summary[State.INSIDE]} |
-
-
-
-
-
-
- |
- {Array.from({ length: TURNS }, (_, i) => (
- {i + 1} |
- ))}
-
-
-
- {Object.entries(rows).map(([key, values]) => {
- const det = details[key as keyof typeof details]
- return (
-
-
- {det.title}
- {det.subtitle}
-
- |
-
- {values.map((v, i) => (
- {v} |
- ))}
-
- )
- })}
-
-
- >
- )
-}
-
-function DisplayGrid({ grid, onToggle }: { grid: State[][], onToggle: (x: number, y: number, value: State) => void }) {
- return (
-
- {grid.map((row, y) => (
- row.map((cell, x) => (
-
onToggle(x, y, cell === State.ON ? State.OFF : State.ON)}
- >
- {cell === State.INSIDE ? '🌾' : cell === State.ON ? '🚜' : ''}
-
- ))
- ))}
-
- )
-}
-
-function computeInside(grid: State[][]): State[][] {
- const next = makeGrid(State.INSIDE)
-
- // copy walls, list entry points
- const queue: [number, number][] = []
- for (let y = 0; y < SIDE; y++) {
- for (let x = 0; x < SIDE; x++) {
- if (grid[y][x] === State.ON) {
- next[y][x] = grid[y][x]
- } else if (y === 0 || x === 0 || y === SIDE - 1 || x === SIDE - 1) {
- next[y][x] = State.OFF
- queue.push([x, y])
- }
- }
- }
-
- // flood fill
- const neighbors = [
- [-1, 0],
- [1, 0],
- [0, -1],
- [0, 1],
- ]
- while (queue.length) {
- const [x, y] = queue.shift()!
- for (const [dx, dy] of neighbors) {
- const nx = x + dx
- const ny = y + dy
- if (nx < 0 || nx >= SIDE || ny < 0 || ny >= SIDE) continue
- if (grid[ny][nx] !== State.OFF) continue
- if (next[ny][nx] === State.OFF) continue
- next[ny][nx] = State.OFF
- queue.push([nx, ny])
- }
- }
-
- return next
-}
-
-function counts(grid: State[][]): Record {
- const result = {
- [State.OFF]: 0,
- [State.ON]: 0,
- [State.INSIDE]: 0,
- }
- for (const row of grid) {
- for (const cell of row) {
- result[cell]++
- }
- }
- return result
-}
-
-const details = {
- total: {
- title: 'Total gains',
- subtitle: 'Total earnings from all fields after N turns.',
- formula: (
-
- f
- {'('}
-
- n
-
- {')'}
- =
- fields
- ×
- 10
- ×
- n
- -
- cost
-
- )
- },
- totalSell: {
- title: 'Total after sale',
- subtitle: 'Total earnings from all fields after N turns,\nafter having sold the farms.',
- formula: (
-
- f
- {'('}
-
- n
-
- {')'}
- =
- fields
- ×
- 10
- ×
- n
- -
- cost
- /
- 2
-
- )
- },
- both: {
- title: 'Both',
- subtitle: 'Total earnings from all fields after N turns,\nearnings are accumulated in the bank and not spent.\nGains are only realized at the end.',
- formula: (
-
- f
- {'('}
-
- n
-
- {')'}
- =
- fields
- ×
- 10
- +
- f
- {'('}
-
- n
- -
- 1
-
- {')'}
- ×
- 1.2
-
- )
- },
- bank: {
- title: 'Bank',
- subtitle: 'Initial cost of the farms is kept frozen in the bank instead,\nsurplus is spent every turn.',
- formula: (
-
- f
- {'('}
-
- n
-
- {')'}
- =
- cost
- ×
- 0.2
- ×
- n
-
- )
- },
- bankCompound: {
- title: 'Bank (accumulate)',
- subtitle: 'Initial cost of the farms is kept in the bank,\nearnings accumulate every turn and are not spent.\nGains are only realized at the end.',
- formula: (
-
- f
- {'('}
-
- n
-
- {')'}
- =
- cost
- ×
- {'('}
-
-
- 1.2
- n
-
- -
- 1
-
- {')'}
-
- )
- }
-} as const
-
-
-declare global {
- namespace JSX {
- interface IntrinsicElements {
- math: React.DetailedHTMLProps & { display?: 'block' | 'inline' }, HTMLElement>
- mrow: React.DetailedHTMLProps, HTMLElement>
- mi: React.DetailedHTMLProps, HTMLElement>
- mn: React.DetailedHTMLProps, HTMLElement>
- mo: React.DetailedHTMLProps & { fence?: boolean }, HTMLElement>
- msup: React.DetailedHTMLProps, HTMLElement>
- munderover: React.DetailedHTMLProps, HTMLElement>
- }
- }
-}
\ No newline at end of file
diff --git a/src/pages/artisan-td-calc/styles.module.css b/src/pages/artisan-td-calc/styles.module.css
deleted file mode 100644
index 4aa92af..0000000
--- a/src/pages/artisan-td-calc/styles.module.css
+++ /dev/null
@@ -1,85 +0,0 @@
-.main {
- padding: 1em;
-
- height: 100dvh;
- width: 100dvw;
-
- >* {
- position: relative;
- z-index: 1;
- }
-}
-
-.grid {
- display: grid;
- grid-template-columns: repeat(var(--side), 100px);
- grid-template-rows: repeat(var(--side), 1fr);
-}
-
-.cell {
- aspect-ratio: 1;
- border: 1px solid currentColor;
- text-align: center;
- font-size: 50px;
- cursor: pointer;
-
- &[data-state="on"] {
- background-color: gray;
- }
-
- &[data-state="off"] {
- background-color: black;
-
- &:hover {
- background-color: #333;
- }
- }
-
- &[data-state="in"] {
- background-color: green;
- }
-}
-
-.table {
- margin-bottom: 1em;
- border-collapse: collapse;
-
- th,
- td {
- border: 1px solid currentColor;
- }
-
- th:empty {
- border: none;
- }
-
- th,
- td {
- padding: 0.5em;
- }
-
- td,
- thead th {
- min-width: calc(3ch + 1em);
- font-variant-numeric: tabular-nums;
- text-align: right;
- }
-
- th[scope="row"] {
- [data-title] {
- margin: 0;
- }
-
- [data-subtitle] {
- font-weight: normal;
- margin: 0;
- white-space: pre-wrap;
- font-size: smaller;
- }
-
- math {
- margin: 0.5em;
- opacity: 0.5;
- }
- }
-}
\ No newline at end of file
diff --git a/src/router.ts b/src/router.ts
index 8543006..5092443 100644
--- a/src/router.ts
+++ b/src/router.ts
@@ -9,8 +9,9 @@ import perlin_ripples_image from "./pages/perlin-ripples/screen.png"
import paint_worklet_image from "./pages/paint-worklet/screen.png"
import lightning_image from "./pages/lightning/screen.png"
import bird_inverse_kinematics_image from "./pages/bird-inverse-kinematics/screen.png"
+import ants_image from "./pages/ants/screen.png"
-export type Routes = "wave-function-collapse" | "spider-inverse-kinematics" | "quad-tree" | "pong-pang" | "perlin-ripples" | "paint-worklet" | "modern-modal" | "lightning" | "fragment-portal" | "bird-inverse-kinematics" | "artisan-td-calc" | "ants"
+export type Routes = "wave-function-collapse" | "spider-inverse-kinematics" | "quad-tree" | "pong-pang" | "perlin-ripples" | "paint-worklet" | "modern-modal" | "lightning" | "fragment-portal" | "bird-inverse-kinematics" | "ants"
export type RouteMeta = {
title: string
@@ -138,23 +139,14 @@ export const ROUTES = {
firstAdded: 1717339261000
},
},
- "artisan-td-calc": {
- Component: lazy(() => import("./pages/artisan-td-calc/index.tsx")),
- meta: {
- title: 'Artisan TD calculator',
- },
- git: {
- lastModified: 1723588686000,
- firstAdded: 1723588686000
- },
- },
"ants": {
Component: lazy(() => import("./pages/ants/index.tsx")),
meta: {
title: 'Ants',
+ image: ants_image
},
git: {
- lastModified: 1728127860000,
+ lastModified: 1728128584000,
firstAdded: 1727995709000
},
}