Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support INT rules #13

Merged
merged 3 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,14 @@ <h2>Data</h2>
<h2>Note</h2>
<ul>
<li>
Outer-totalistic cellular automata are supported (without B0).
Outer-totalistic rules and isotropic non-totalistic rules are
supported (without B0).
</li>
<li>The supplied pattern must be a phase of an oscillator.</li>
<li>The maximum period that can be analyzed is 50,000.</li>
<li>
The maximum period that can be analyzed is 50,000 for outer
totalistic rules and 2,000 for isotropic non-totalistic rules.
</li>
</ul>
</section>
<section>
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
17 changes: 14 additions & 3 deletions src/lib/WorldWithHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down
8 changes: 5 additions & 3 deletions src/lib/analyzeOscillator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
Expand Down
22 changes: 17 additions & 5 deletions src/lib/runOscillator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,39 @@ 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;
};

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,
Expand All @@ -36,5 +48,5 @@ export function runOscillator(
}
}

throw new Error("Error: analyzeOscillator");
throw new Error("Error: Oscillator not detected");
}
24 changes: 16 additions & 8 deletions src/worker.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down