94 lines
2.6 KiB
TypeScript
94 lines
2.6 KiB
TypeScript
import { numericGridSize, seededRandom } from './caRuntime.js'
|
|
import type { CaClass, JsonObject, SceneParams } from './types.js'
|
|
|
|
export interface InitialConditionResult {
|
|
type: 'cells'
|
|
cells: number[][]
|
|
generator: {
|
|
kind: string
|
|
} & JsonObject
|
|
}
|
|
|
|
export interface InitialConditionRuntimeInput {
|
|
settings: SceneParams
|
|
caClass: CaClass
|
|
params: JsonObject
|
|
}
|
|
|
|
export interface InitialConditionRuntime {
|
|
id: string
|
|
label: string
|
|
generate: (input: InitialConditionRuntimeInput) => InitialConditionResult
|
|
}
|
|
|
|
const initialConditionRuntimes = new Map<string, InitialConditionRuntime>()
|
|
|
|
function clampDensity(value: unknown) {
|
|
return Math.max(0, Math.min(1, typeof value === 'number' ? value : 0.28))
|
|
}
|
|
|
|
function randomSoup({ settings, caClass, params }: InitialConditionRuntimeInput): InitialConditionResult {
|
|
const density = clampDensity(params.density)
|
|
const seed = typeof params.seed === 'string' ? params.seed : 'studio-seed'
|
|
const random = seededRandom(seed)
|
|
const [width, height, depth] = numericGridSize(settings.simulation?.grid, caClass.dimensions)
|
|
const cells: number[][] = []
|
|
|
|
for (let z = 0; z < depth; z += 1) {
|
|
for (let y = 0; y < height; y += 1) {
|
|
for (let x = 0; x < width; x += 1) {
|
|
if (random() < density) cells.push([x, y, z])
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
type: 'cells',
|
|
cells,
|
|
generator: {
|
|
kind: 'random-soup',
|
|
density,
|
|
seed
|
|
}
|
|
}
|
|
}
|
|
|
|
export function registerInitialConditionRuntime(
|
|
runtime: InitialConditionRuntime,
|
|
options: { replace?: boolean } = {}
|
|
) {
|
|
if (!runtime.id.trim()) throw new Error('Initial condition runtime id is required')
|
|
if (initialConditionRuntimes.has(runtime.id) && !options.replace) {
|
|
throw new Error(`Initial condition runtime already registered: ${runtime.id}`)
|
|
}
|
|
initialConditionRuntimes.set(runtime.id, runtime)
|
|
}
|
|
|
|
export function listInitialConditionRuntimes() {
|
|
return [...initialConditionRuntimes.values()]
|
|
}
|
|
|
|
export function getInitialConditionRuntime(runtimeId: string) {
|
|
return initialConditionRuntimes.get(runtimeId) ?? null
|
|
}
|
|
|
|
export function generateInitialCondition(runtimeId: string, input: InitialConditionRuntimeInput) {
|
|
const runtime = getInitialConditionRuntime(runtimeId)
|
|
if (!runtime) throw new Error(`Initial condition runtime unavailable: ${runtimeId}`)
|
|
|
|
const result = runtime.generate(input)
|
|
if (result.type !== 'cells' || !Array.isArray(result.cells)) {
|
|
throw new Error(`Initial condition runtime returned an invalid result: ${runtimeId}`)
|
|
}
|
|
return result
|
|
}
|
|
|
|
registerInitialConditionRuntime(
|
|
{
|
|
id: 'random-soup',
|
|
label: 'Random soup',
|
|
generate: randomSoup
|
|
},
|
|
{ replace: true }
|
|
)
|