46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
import { resolveBoundaryCondition, resolveBoundaryIndex } from '../caRuntime.js'
|
|||
|
|
import type { Cells, SceneParams } from '../types.js'
|
||
|
|
import { emptyCellsLike } from './cellGrid.js'
|
||
|
|
|
||
|
|
function parseOuterTotalisticRule(ruleId: string) {
|
||
|
|
const match = /^B([0-8]*)\/S([0-8]*)$/i.exec(ruleId)
|
||
|
|
if (!match) return { birth: new Set([3]), survival: new Set([2, 3]) }
|
||
|
|
|
||
|
|
return {
|
||
|
|
birth: new Set(match[1].split('').map(Number)),
|
||
|
|
survival: new Set(match[2].split('').map(Number))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function stepOuterTotalistic2d(cells: Cells, settings: SceneParams) {
|
||
|
|
const rule = parseOuterTotalisticRule(settings.simulation?.ruleId ?? 'B3/S23')
|
||
|
|
const next = emptyCellsLike(cells)
|
||
|
|
const height = cells.length
|
||
|
|
const width = cells[0]?.length ?? 0
|
||
|
|
const boundary = resolveBoundaryCondition(settings.simulation?.grid)
|
||
|
|
|
||
|
|
for (let y = 0; y < height; y += 1) {
|
||
|
|
for (let x = 0; x < width; x += 1) {
|
||
|
|
let neighbours = 0
|
||
|
|
|
||
|
|
for (let dy = -1; dy <= 1; dy += 1) {
|
||
|
|
for (let dx = -1; dx <= 1; dx += 1) {
|
||
|
|
if (dx === 0 && dy === 0) continue
|
||
|
|
|
||
|
|
const rawX = x + dx
|
||
|
|
const rawY = y + dy
|
||
|
|
const nx = resolveBoundaryIndex(rawX, width, boundary)
|
||
|
|
const ny = resolveBoundaryIndex(rawY, height, boundary)
|
||
|
|
|
||
|
|
if (nx === null || ny === null) continue
|
||
|
|
if (cells[ny][nx]) neighbours += 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
next[y][x] = cells[y][x] ? rule.survival.has(neighbours) : rule.birth.has(neighbours)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return next
|
||
|
|
}
|