diff --git a/.gitignore b/.gitignore
index 1119501c..a7ec0245 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
node_modules/
tmp/
dist/*
+venv/
src/local_configs.js
+
diff --git a/README.md b/README.md
index 40eb4ed6..5208096d 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,10 @@
## Getting started
```shell
+$ python3 -m venv venv # need only once
+
+$ source venv/bin/activate
+
# Install
$ yarn install
diff --git a/pages/garden.html b/pages/garden.html
new file mode 100644
index 00000000..3f4ba865
--- /dev/null
+++ b/pages/garden.html
@@ -0,0 +1,28 @@
+
+
+ Darwin's Garden
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/html-generator/generate.py b/src/html-generator/generate.py
index 6bf54d30..ad9fdd30 100644
--- a/src/html-generator/generate.py
+++ b/src/html-generator/generate.py
@@ -1,3 +1,5 @@
+#! /usr/bin/env python3
+
import os, sys
from glob import glob
diff --git a/src/pages/lab/layout.tsx b/src/pages/lab/layout.tsx
index 39857e64..7355dcea 100644
--- a/src/pages/lab/layout.tsx
+++ b/src/pages/lab/layout.tsx
@@ -32,6 +32,7 @@ const App = () => {
+
diff --git a/src/simulations/garden/drawable.ts b/src/simulations/garden/drawable.ts
new file mode 100644
index 00000000..d165d81c
--- /dev/null
+++ b/src/simulations/garden/drawable.ts
@@ -0,0 +1,16 @@
+/**
+# Drawable
+## 概要
+状態を描画処理と切り離すためのインターフェース
+ */
+
+export type DrawableState = {
+ readonly case: string
+}
+export type DrawableStateInvisible = {
+ readonly case: "invisible"
+}
+
+export interface Drawable {
+ drawableState(): State
+}
\ No newline at end of file
diff --git a/src/simulations/garden/drawable_types.ts b/src/simulations/garden/drawable_types.ts
new file mode 100644
index 00000000..b6471e3e
--- /dev/null
+++ b/src/simulations/garden/drawable_types.ts
@@ -0,0 +1,7 @@
+import { Life } from "./life"
+import { Terrain } from "./terrain"
+import { World } from "./world"
+
+type AnyDrawable = World | Terrain | Life
+
+export type AnyDrawableStates = ReturnType
diff --git a/src/simulations/garden/html_arguments.json b/src/simulations/garden/html_arguments.json
new file mode 100644
index 00000000..012338e7
--- /dev/null
+++ b/src/simulations/garden/html_arguments.json
@@ -0,0 +1,6 @@
+{
+ "page_title": "Darwin's Garden",
+ "og_description": "",
+ "og_image": "",
+ "script_path": "../dist/garden.js"
+}
\ No newline at end of file
diff --git a/src/simulations/garden/layout.tsx b/src/simulations/garden/layout.tsx
new file mode 100644
index 00000000..700fa5d1
--- /dev/null
+++ b/src/simulations/garden/layout.tsx
@@ -0,0 +1,21 @@
+import p5 from "p5"
+import React from "react"
+import ReactDOM from "react-dom"
+import { DetailPage, ScreenshotButtonDefault } from "../../react-components/lab/detail_page"
+import { main, getTimestamp } from "./source"
+
+const App = () => {
+ const screenshotButton: ScreenshotButtonDefault = {
+ kind: "default",
+ getTimestamp,
+ getDescription: () => document.location.search
+ }
+ return (
+
+
+ )
+}
+
+ReactDOM.render(, document.getElementById("root"))
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const sketch = new p5(main)
diff --git a/src/simulations/garden/life.ts b/src/simulations/garden/life.ts
new file mode 100644
index 00000000..80c1a5ac
--- /dev/null
+++ b/src/simulations/garden/life.ts
@@ -0,0 +1,26 @@
+import { Vector } from "src/classes/physics"
+import { WorldObject } from "./world_object"
+
+export type LifeDrawableState = {
+ readonly case: "life"
+}
+
+export class Life implements WorldObject {
+ public get position(): Vector {
+ return this._position
+ }
+
+ private _position: Vector
+
+ public constructor(
+ initialPosition: Vector,
+ ) {
+ this._position = initialPosition
+ }
+
+ public drawableState(): LifeDrawableState {
+ return {
+ case: "life",
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/simulations/garden/p5_drawer.ts b/src/simulations/garden/p5_drawer.ts
new file mode 100644
index 00000000..7fe5dd42
--- /dev/null
+++ b/src/simulations/garden/p5_drawer.ts
@@ -0,0 +1,55 @@
+import p5 from "p5"
+import { AnyDrawableStates } from "./drawable_types"
+import { LifeDrawableState } from "./life"
+import { TerrainDrawableState } from "./terrain"
+import { WorldDrawableState } from "./world"
+
+type AnyDrawableStateCases = AnyDrawableStates["case"]
+const drawPriority: { [K in AnyDrawableStateCases]: number } = { // 数字の小さい方が先に描画
+ world: 0,
+ terrain: 10,
+ life: 20,
+}
+
+export class P5Drawer {
+ public constructor(
+ private readonly p: p5,
+ ) {
+ }
+
+ public drawAll(states: DrawableState[]): void {
+ this.p.background(0, 0xFF);
+
+ [...states]
+ .sort((lhs, rhs) => drawPriority[lhs.case] - drawPriority[rhs.case])
+ .forEach(state => this.draw(state))
+ }
+
+ private draw(state: DrawableState): void {
+ switch (state.case) {
+ case "world":
+ this.drawWorld(state)
+ return
+ case "terrain":
+ this.drawTerrain(state)
+ return
+ case "life":
+ this.drawLife(state)
+ return
+ default: {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const _: never = state
+ return
+ }
+ }
+ }
+
+ private drawWorld(state: WorldDrawableState): void {
+ }
+
+ private drawTerrain(state: TerrainDrawableState): void {
+ }
+
+ private drawLife(state: LifeDrawableState): void {
+ }
+}
\ No newline at end of file
diff --git a/src/simulations/garden/source.ts b/src/simulations/garden/source.ts
new file mode 100644
index 00000000..0a3b67a5
--- /dev/null
+++ b/src/simulations/garden/source.ts
@@ -0,0 +1,37 @@
+import p5 from "p5"
+import { Vector } from "src/classes/physics"
+import { defaultCanvasParentId } from "../../react-components/common/default_canvas_parent_id"
+import { P5Drawer } from "./p5_drawer"
+import { World } from "./world"
+
+let t = 0
+const canvasId = "canvas"
+const cellSize = 4
+const worldSize = new Vector(200, 200)
+const fieldSize = worldSize.mult(cellSize)
+
+export const main = (p: p5): void => {
+ const world = new World(worldSize)
+ const drawer = new P5Drawer(p)
+
+ p.setup = () => {
+ const canvas = p.createCanvas(fieldSize.x, fieldSize.y)
+ canvas.id(canvasId)
+ canvas.parent(defaultCanvasParentId)
+
+ p.background(0, 0xFF)
+ }
+
+ p.draw = () => {
+ const drawableObjects = [
+ world.drawableState(),
+ ...world.getDrawableObjects().map(obj => obj.drawableState()),
+ ]
+ drawer.drawAll(drawableObjects)
+ t += 1
+ }
+}
+
+export const getTimestamp = (): number => {
+ return t
+}
diff --git a/src/simulations/garden/terrain.ts b/src/simulations/garden/terrain.ts
new file mode 100644
index 00000000..1af254f1
--- /dev/null
+++ b/src/simulations/garden/terrain.ts
@@ -0,0 +1,31 @@
+import { Vector } from "src/classes/physics"
+import { WorldObject } from "./world_object"
+
+type TerrainStateNone = {
+ readonly case: "none"
+}
+type TerrainState = TerrainStateNone
+type TerrainStates = TerrainState["case"]
+
+export type TerrainDrawableState = {
+ readonly case: "terrain"
+ readonly state: TerrainStates
+}
+
+export class Terrain implements WorldObject {
+ private state: TerrainState
+
+ public constructor(
+ public readonly position: Vector,
+ initialState: TerrainState,
+ ) {
+ this.state = initialState
+ }
+
+ public drawableState(): TerrainDrawableState {
+ return {
+ case: "terrain",
+ state: this.state.case,
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/simulations/garden/world.ts b/src/simulations/garden/world.ts
new file mode 100644
index 00000000..a87788e7
--- /dev/null
+++ b/src/simulations/garden/world.ts
@@ -0,0 +1,32 @@
+import { Vector } from "src/classes/physics"
+import { Drawable } from "./drawable"
+import { Life } from "./life"
+import { Terrain } from "./terrain"
+
+type AnyWorldObject = Terrain | Life
+
+export type WorldDrawableState = {
+ readonly case: "world"
+}
+
+export class World implements Drawable {
+ private terrains: Terrain[]
+
+ public constructor(
+ public readonly size: Vector,
+ ) {
+ }
+
+ public drawableState(): WorldDrawableState {
+ return {
+ case: "world",
+ }
+ }
+
+ public calculate(): void {
+ }
+
+ public getDrawableObjects(): AnyWorldObject[] {
+ return []
+ }
+}
\ No newline at end of file
diff --git a/src/simulations/garden/world_object.ts b/src/simulations/garden/world_object.ts
new file mode 100644
index 00000000..3488a7e4
--- /dev/null
+++ b/src/simulations/garden/world_object.ts
@@ -0,0 +1,12 @@
+/**
+# WorldObject
+## 概要
+World上に存在する物体/状態
+ */
+
+import { Vector } from "src/classes/physics"
+import { Drawable, DrawableState } from "./drawable"
+
+export interface WorldObject extends Drawable {
+ position: Vector
+}
diff --git a/webpack.config.js b/webpack.config.js
index 4010886b..b2236225 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -24,6 +24,7 @@ module.exports = {
hex_cellular_automata: "./src/simulations/hex_cellular_automata/layout.tsx",
hex_cellular_automata_autosearch: "./src/simulations/hex_cellular_automata_autosearch/layout.tsx",
kaleidoscope_v2: "./src/simulations/kaleidoscope_v2/layout.tsx",
+ garden: "./src/simulations/garden/layout.tsx",
},
output: {
path: path.resolve(__dirname, "dist"),