From b3aadd024ebbfc2047419cb3d2ac6e681ef212bf Mon Sep 17 00:00:00 2001 From: Rei Date: Thu, 24 Oct 2024 23:51:37 +0900 Subject: [PATCH] feat: support INT rules (#13) * feat: support INT rules * feat: improve error message * feat: improve error message --- index.html | 8 ++++++-- package-lock.json | 8 ++++---- package.json | 2 +- src/lib/WorldWithHistory.ts | 17 ++++++++++++++--- src/lib/analyzeOscillator.test.ts | 8 +++++--- src/lib/runOscillator.ts | 22 +++++++++++++++++----- src/worker.ts | 24 ++++++++++++++++-------- 7 files changed, 63 insertions(+), 26 deletions(-) diff --git a/index.html b/index.html index bdfcdc0..5ac14d9 100644 --- a/index.html +++ b/index.html @@ -187,10 +187,14 @@

Data

Note

diff --git a/package-lock.json b/package-lock.json index ce37cef..51b71a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "devDependencies": { - "@ca-ts/algo": "npm:@jsr/ca-ts__algo@^0.5.0", + "@ca-ts/algo": "npm:@jsr/ca-ts__algo@^0.6.0", "@ca-ts/rle": "npm:@jsr/ca-ts__rle@^0.8.0", "@ca-ts/rule": "npm:@jsr/ca-ts__rule@^0.4.0", "typescript": "^5.6.3", @@ -20,9 +20,9 @@ }, "node_modules/@ca-ts/algo": { "name": "@jsr/ca-ts__algo", - "version": "0.5.0", - "resolved": "https://npm.jsr.io/~/11/@jsr/ca-ts__algo/0.5.0.tgz", - "integrity": "sha512-KQM7g9Uc8hf/6R7LXkGgjZLsZACh1qjyHs560ruh49c/yAPFNKKllJn0dxFcZEe98KYy1oxvJ5fogH5I5JhKFw==", + "version": "0.6.0", + "resolved": "https://npm.jsr.io/~/11/@jsr/ca-ts__algo/0.6.0.tgz", + "integrity": "sha512-mIBtSCUeeKMLcDgPIb380gyBjM+ctWSS0JZGgb7lan5iuFlZJ3Q1dmiClKIQ4mI4pxCpVa0LKprmszv+U0Zxnw==", "dev": true }, "node_modules/@ca-ts/rle": { diff --git a/package.json b/package.json index a3656cb..759dfcf 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "test": "vitest" }, "devDependencies": { - "@ca-ts/algo": "npm:@jsr/ca-ts__algo@^0.5.0", + "@ca-ts/algo": "npm:@jsr/ca-ts__algo@^0.6.0", "@ca-ts/rle": "npm:@jsr/ca-ts__rle@^0.8.0", "@ca-ts/rule": "npm:@jsr/ca-ts__rule@^0.4.0", "typescript": "^5.6.3", diff --git a/src/lib/WorldWithHistory.ts b/src/lib/WorldWithHistory.ts index c81edca..e4cfe67 100644 --- a/src/lib/WorldWithHistory.ts +++ b/src/lib/WorldWithHistory.ts @@ -22,10 +22,16 @@ export class WorldWithHistory { constructor({ cells, bufferSize, - transition, + rule, }: { cells: { x: number; y: number }[]; - transition: { birth: number[]; survive: number[] }; + rule: + | { + transition: { birth: number[]; survive: number[] }; + } + | { + intTransition: { birth: string[]; survive: string[] }; + }; bufferSize?: number; }) { this.bufferSize = bufferSize ?? 32; @@ -35,7 +41,12 @@ export class WorldWithHistory { width: sizeX + this.bufferSize, height: sizeY + this.bufferSize, }); - this.bitWorld.setRule(transition); + if ("transition" in rule && rule.transition !== undefined) { + this.bitWorld.setRule(rule.transition); + } else if ("intTransition" in rule && rule.intTransition !== undefined) { + this.bitWorld.setINTRule(rule.intTransition); + } + setCellsToBitGrid(this.bitWorld.bitGrid, cells, { sizeX, sizeY }); this.initialBitGrid = this.bitWorld.bitGrid.clone(); diff --git a/src/lib/analyzeOscillator.test.ts b/src/lib/analyzeOscillator.test.ts index 3250adb..e97b2c7 100644 --- a/src/lib/analyzeOscillator.test.ts +++ b/src/lib/analyzeOscillator.test.ts @@ -8,9 +8,11 @@ describe("analyzeOscillator", () => { cells: parseRLE(`ooo`) .cells.filter((x) => x.state === 1) .map((x) => x.position), - transition: { - birth: [3], - survive: [2, 3], + rule: { + transition: { + birth: [3], + survive: [2, 3], + }, }, maxGeneration: 1000, }); diff --git a/src/lib/runOscillator.ts b/src/lib/runOscillator.ts index 4922a9a..9421d78 100644 --- a/src/lib/runOscillator.ts +++ b/src/lib/runOscillator.ts @@ -2,7 +2,13 @@ import { WorldSizeError, WorldWithHistory } from "./WorldWithHistory"; export type RunOscillatorConfig = { cells: { x: number; y: number }[]; - transition: { birth: number[]; survive: number[] }; + rule: + | { + transition: { birth: number[]; survive: number[] }; + } + | { + intTransition: { birth: string[]; survive: string[] }; + }; maxGeneration: number; }; @@ -10,19 +16,25 @@ export type RunOscillatorResult = { world: WorldWithHistory; }; +export class MaxGenerationError extends Error { + constructor(maxGen: number) { + super("Maximum generation is " + maxGen); + } +} + export function runOscillator( config: RunOscillatorConfig ): RunOscillatorResult { - const { cells, transition, maxGeneration } = config; + const { cells, rule, maxGeneration } = config; let bufferSize = 32; for (let i = 0; i < 5; i++) { try { - const world = new WorldWithHistory({ cells, bufferSize, transition }); + const world = new WorldWithHistory({ cells, bufferSize, rule }); const result = world.run({ forceStop: () => world.getGen() >= maxGeneration, }); if (result === "forced-stop") { - throw new Error("Max Generations."); + throw new MaxGenerationError(config.maxGeneration); } return { world, @@ -36,5 +48,5 @@ export function runOscillator( } } - throw new Error("Error: analyzeOscillator"); + throw new Error("Error: Oscillator not detected"); } diff --git a/src/worker.ts b/src/worker.ts index cf61d9e..394b3b4 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -1,6 +1,7 @@ import { analyzeOscillator, type AnalyzeResult } from "./lib/analyzeOscillator"; import { parseRLE } from "@ca-ts/rle"; import { parseRule } from "@ca-ts/rule"; +import { MaxGenerationError } from "./lib/runOscillator"; export type WorkerRequestMessage = { kind: "request-analyze"; @@ -37,14 +38,12 @@ function handleRequest(data: WorkerRequestMessage): WorkerResponseMessage { }; } - if (rule.type !== "outer-totalistic") { + if (rule.type === "outer-totalistic" && rule.transition.birth.includes(0)) { return { kind: "response-error", - message: "Unsupported rule", + message: "Rules containing B0 is not supported", }; - } - - if (rule.transition.birth.includes(0)) { + } else if (rule.type === "int" && rule.transition.birth.includes("0")) { return { kind: "response-error", message: "Rules containing B0 is not supported", @@ -58,16 +57,25 @@ function handleRequest(data: WorkerRequestMessage): WorkerResponseMessage { message: "Empty pattern", }; } - + const maxGeneration = rule.type === "int" ? 2_000 : 50_000; try { const result = analyzeOscillator({ cells: cells, - transition: rule.transition, - maxGeneration: 50_000, + rule: + rule.type === "int" + ? { intTransition: rule.transition } + : { transition: rule.transition }, + maxGeneration: maxGeneration, }); return { kind: "response-analyzed", data: result }; } catch (error) { console.error(error); + if (error instanceof MaxGenerationError) { + return { + kind: "response-error", + message: `maximum period is ${maxGeneration.toLocaleString()}`, + }; + } return { kind: "response-error", message: "Analyzation Error",