diff --git a/PROJECT_DESCRIPTION.md b/PROJECT_DESCRIPTION.md index fd65060..987bf11 100644 --- a/PROJECT_DESCRIPTION.md +++ b/PROJECT_DESCRIPTION.md @@ -36,7 +36,7 @@ npm run build | Need | Algorithm(s) | Module | Example | | ---- | ------------ | ------ | ------- | | Grid pathfinding | `astar`, `dijkstra`, `jumpPointSearch`, `computeFlowField`, `buildNavMesh`, `findNavMeshPath`, `manhattanDistance`, `gridFromString` | `pathfinding/astar.ts`, `pathfinding/dijkstra.ts`, `pathfinding/jumpPointSearch.ts`, `pathfinding/flowField.ts`, `pathfinding/navMesh.ts` | `examples/astar.ts`, `examples/flowField.ts`, `examples/navMesh.ts` | -| Procedural textures & terrain | `perlin`, `perlin3D`, `simplex2D`, `simplex3D`, `worley`, `worleySample`, `waveFunctionCollapse`, `cellularAutomataCave`, `poissonDiskSampling`, `computeVoronoiDiagram` | `procedural/*.ts` | `examples/simplex.ts`, `examples/worley.ts`, `examples/waveFunctionCollapse.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts` | +| Procedural textures & terrain | `perlin`, `perlin3D`, `simplex2D`, `simplex3D`, `worley`, `worleySample`, `waveFunctionCollapse`, `cellularAutomataCave`, `poissonDiskSampling`, `computeVoronoiDiagram`, `diamondSquare`, `generateLSystem` | `procedural/*.ts` | `examples/simplex.ts`, `examples/worley.ts`, `examples/waveFunctionCollapse.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/diamondSquare.ts`, `examples/lSystem.ts` | | Spatial queries & collision | `Quadtree`, `aabbCollision`, `aabbIntersection`, `satCollision`, `circleRayIntersection`, `sweptAABB` | `spatial/*.ts` | `examples/sat.ts` | | Web performance & UI throttling | `debounce`, `throttle`, `LRUCache`, `memoize`, `deduplicateRequest`, `clearRequestDedup`, `calculateVirtualRange` | `util/*.ts` | `examples/requestDedup.ts`, `examples/virtualScroll.ts` | | Text & search | `fuzzySearch`, `fuzzyScore`, `Trie`, `binarySearch`, `levenshteinDistance` | `search/*.ts` | `examples/search.ts` | diff --git a/README.md b/README.md index a19cd82..6c0fcd0 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ CDN usage: | Goal | Algorithms | Import From | Example | | ---- | ---------- | ----------- | ------- | | Pathfinding & navigation | `astar`, `dijkstra`, `jumpPointSearch`, `computeFlowField`, `buildNavMesh`, `findNavMeshPath`, `manhattanDistance`, `gridFromString` | `pathfinding/astar.ts`, `pathfinding/dijkstra.ts`, `pathfinding/jumpPointSearch.ts`, `pathfinding/flowField.ts`, `pathfinding/navMesh.ts` | `examples/astar.ts`, `examples/flowField.ts`, `examples/navMesh.ts` | -| Procedural generation | `perlin`, `perlin3D`, `simplex2D`, `simplex3D`, `worley`, `worleySample`, `waveFunctionCollapse`, `cellularAutomataCave`, `poissonDiskSampling`, `computeVoronoiDiagram` | `procedural/*.ts` | `examples/simplex.ts`, `examples/worley.ts`, `examples/waveFunctionCollapse.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts` | +| Procedural generation | `perlin`, `perlin3D`, `simplex2D`, `simplex3D`, `worley`, `worleySample`, `waveFunctionCollapse`, `cellularAutomataCave`, `poissonDiskSampling`, `computeVoronoiDiagram`, `diamondSquare`, `generateLSystem` | `procedural/*.ts` | `examples/simplex.ts`, `examples/worley.ts`, `examples/waveFunctionCollapse.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/diamondSquare.ts`, `examples/lSystem.ts` | | Spatial queries & collision | `Quadtree`, `aabbCollision`, `aabbIntersection`, `satCollision`, `circleRayIntersection`, `sweptAABB` | `spatial/*.ts` | `examples/sat.ts` | | AI behaviours & crowds | `seek`, `flee`, `arrive`, `pursue`, `wander`, `updateBoids`, `BehaviorTree`, `rvoStep` | `ai/steering.ts`, `ai/boids.ts`, `ai/behaviorTree.ts`, `ai/rvo.ts` | `examples/steering.ts`, `examples/boids.ts`, `examples/rvo.ts` | | Web performance & UI | `debounce`, `throttle`, `LRUCache`, `memoize`, `deduplicateRequest`, `clearRequestDedup`, `calculateVirtualRange` | `util/*.ts` | `examples/requestDedup.ts`, `examples/virtualScroll.ts` | @@ -52,7 +52,7 @@ npm run size # Enforce bundle size budget - Milestone 0.2 next targets crowd-flow integrations (RVO + flow fields) and behaviour-tree decorators for richer AI control. - Milestone 0.4 plans a procedural + gameplay systems toolkit (Wave Function Collapse, dungeon suite, L-systems, game loop, camera, particles, inventory, combat, save/load, and more). -Examples live under `examples/` and can be executed with `tsx`/`ts-node` or compiled for the browser. See `examples/astar.ts`, `examples/flowField.ts`, `examples/navMesh.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/steering.ts`, `examples/boids.ts`, `examples/requestDedup.ts`, `examples/search.ts`, `examples/graph.ts`, `examples/geometry.ts`, `examples/visual.ts`, `examples/sat.ts`, `examples/simplex.ts`, and `examples/worley.ts` for quick starts. The `examples` registry exported from `src/index.ts` provides a typed index you can traverse programmatically. +Examples live under `examples/` and can be executed with `tsx`/`ts-node` or compiled for the browser. See `examples/astar.ts`, `examples/flowField.ts`, `examples/navMesh.ts`, `examples/cellularAutomata.ts`, `examples/poissonDisk.ts`, `examples/voronoi.ts`, `examples/diamondSquare.ts`, `examples/lSystem.ts`, `examples/steering.ts`, `examples/boids.ts`, `examples/requestDedup.ts`, `examples/search.ts`, `examples/graph.ts`, `examples/geometry.ts`, `examples/visual.ts`, `examples/sat.ts`, `examples/simplex.ts`, and `examples/worley.ts` for quick starts. The `examples` registry exported from `src/index.ts` provides a typed index you can traverse programmatically. ## Contributing 1. Fork the repository. diff --git a/ROADMAP.md b/ROADMAP.md index 1cd4bb3..de3b1a9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,15 +1,17 @@ # LLM Algorithms Roadmap ## Milestone 0.1.0 – Foundational Toolkit + - [x] Scaffold project structure, npm metadata, and documentation - [x] Migrate runtime codebase to strict TypeScript with shared type definitions -- [x] Implement core algorithms (A*, Dijkstra, Perlin, Quadtree, AABB, data/search utilities) +- [x] Implement core algorithms (A\*, Dijkstra, Perlin, Quadtree, AABB, data/search utilities) - [x] Add steering behaviours and SAT collision module - [x] Provide Vitest coverage for representative algorithms -- [x] Ship runnable TypeScript examples (A*, steering, SAT) +- [x] Ship runnable TypeScript examples (A\*, steering, SAT) - [x] Configure ESLint, Prettier, and CI workflow integration ## Milestone 0.2.0 – Procedural & AI Expansion (In Progress) + - [x] Implement Simplex noise generator with tests - [x] Implement Worley noise generator with tests - [x] Add boids flocking simulation and unit coverage @@ -24,6 +26,7 @@ - [x] Provide navigation mesh (navmesh) helper for irregular terrain ## Milestone 0.3.0 – Web Performance & Data Pipelines + - [x] Introduce request deduplication helper - [x] Ship virtual scrolling utilities - [x] Add diff/patch helpers for nested JSON structures @@ -37,7 +40,7 @@ - [x] Poisson disk sampling for even point distribution - [x] Voronoi diagram helpers for biome/territory generation - [x] Diamond-square terrain height map generator - - [ ] L-system generator for foliage and organic structures + - [x] L-system generator for foliage and organic structures - [ ] Dungeon generation suite (BSP subdivision, rooms & corridors variants) - [ ] Maze algorithms pack (Recursive backtracking, Prim's, Kruskal's, Wilson's, Aldous–Broder, Recursive Division) - Gameplay systems & utilities: @@ -68,6 +71,7 @@ - [ ] Screen transition utilities (fades, wipes, letterboxing) ## Milestone 0.5.0 – Algorithm Vault & Data Structures (Planned) + - **AI & behaviour expansions** - [ ] Finite state machine (FSM) toolkit - [ ] Genetic algorithm utilities @@ -111,6 +115,7 @@ - [ ] Closest pair of points solver for geometry toolkit ## Milestone 1.0.0 – Production Readiness + - [ ] Publish to npm with semver automation and changelog management - [ ] Provide comprehensive documentation site (e.g., VitePress) with interactive demos - [ ] Offer ESM + CJS build outputs and tree-shaking test cases @@ -119,14 +124,16 @@ --- ## Recently Completed Tasks + - TypeScript migration with strict compiler settings - Added steering behaviours and SAT collision detection - Set up Vitest suites and GitHub Actions CI pipeline - Authored usage examples to accelerate onboarding ## Upcoming Focus + 1. Procedural generation enhancements (Worley refinements, Worley-based effects, upcoming Worley variants like Worley F1/F2) 2. Behavioural AI additions (crowd steering via RVO, flow-field integration, behaviour tree decorators) 3. Procedural & systems expansion (Wave Function Collapse, dungeon suite, L-systems, diamond-square, full game systems toolkit) 4. Advanced collision utilities (swept volumes with rotation, broad-phase acceleration structures) -Note: tasks will move to the completed section once merged via the standard branch + PR workflow. + Note: tasks will move to the completed section once merged via the standard branch + PR workflow. diff --git a/docs/index.d.ts b/docs/index.d.ts index 13b0e5e..cc23548 100644 --- a/docs/index.d.ts +++ b/docs/index.d.ts @@ -50,6 +50,7 @@ export const examples: { readonly poissonDiskSampling: 'examples/poissonDisk.ts'; readonly computeVoronoiDiagram: 'examples/voronoi.ts'; readonly diamondSquare: 'examples/diamondSquare.ts'; + readonly generateLSystem: 'examples/lSystem.ts'; }; readonly spatial: { readonly Quadtree: 'examples/sat.ts'; @@ -388,7 +389,6 @@ export interface PoissonDiskOptions { export function poissonDiskSampling(options: PoissonDiskOptions): Point[]; /** -<<<<<<< HEAD * Voronoi site definition. * Use for: labelling regions, associating metadata to cells. * Import: procedural/voronoi.ts @@ -439,7 +439,8 @@ export function computeVoronoiDiagram( sites: ReadonlyArray, options?: VoronoiOptions ): VoronoiCell[]; -======= + +/** * Options configuring the diamond-square fractal algorithm. * Use for: tuning roughness, deterministic height map generation. * Import: procedural/diamondSquare.ts @@ -470,7 +471,60 @@ export interface DiamondSquareResult { * Import: procedural/diamondSquare.ts */ export function diamondSquare(options: DiamondSquareOptions): DiamondSquareResult; ->>>>>>> c977c3c (feat: add diamond-square terrain generator) + +/** + * Stochastic L-system rule with optional weighting. + * Use for: probabilistic grammars, varied foliage, randomised growth. + * Import: procedural/lSystem.ts + */ +export interface StochasticRule { + successor: string; + weight?: number; +} + +/** + * Production rule definition for deterministic or stochastic replacements. + * Import: procedural/lSystem.ts + */ +export type ProductionRule = string | ReadonlyArray; + +/** + * Lindenmayer system ruleset. + * Use for: defining grammar productions. + * Import: procedural/lSystem.ts + */ +export type LSystemRules = Readonly>; + +/** + * L-system options controlling iterations and stochastic behaviour. + * Use for: axiom-driven expansions, deterministic or random sequences. + * Import: procedural/lSystem.ts + */ +export interface LSystemOptions { + axiom: string; + rules: LSystemRules; + iterations: number; + seed?: number; + trackHistory?: boolean; +} + +/** + * L-system generation result containing final string and optional history. + * Use for: caching iteration states, debugging expansions. + * Import: procedural/lSystem.ts + */ +export interface LSystemResult { + result: string; + history: string[]; +} + +/** + * Generates an L-system sequence using deterministic or stochastic rules. + * Use for: foliage grammars, fractal curves, grammar-based systems. + * Performance: O(n × iterations) where n is string length per step. + * Import: procedural/lSystem.ts + */ +export function generateLSystem(options: LSystemOptions): LSystemResult; /** * Simplex noise generator for smooth gradients without directional artifacts. diff --git a/examples/lSystem.ts b/examples/lSystem.ts new file mode 100644 index 0000000..7aefb63 --- /dev/null +++ b/examples/lSystem.ts @@ -0,0 +1,14 @@ +import { generateLSystem } from '../src/index.js'; + +const { result, history } = generateLSystem({ + axiom: 'F', + iterations: 4, + rules: { + F: 'F+F−F−F+F', + }, + trackHistory: true, +}); + +console.log('Final string length:', result.length); +console.log('History states:', history.length); +console.log('Final preview:', result.slice(0, 60)); diff --git a/src/index.ts b/src/index.ts index c1ef5e8..b5526dc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,6 +46,7 @@ export const examples = { poissonDiskSampling: 'examples/poissonDisk.ts', computeVoronoiDiagram: 'examples/voronoi.ts', diamondSquare: 'examples/diamondSquare.ts', + generateLSystem: 'examples/lSystem.ts', }, spatial: { Quadtree: 'examples/sat.ts', @@ -245,19 +246,25 @@ export { cellularAutomataCave } from './procedural/cellularAutomata.js'; export { poissonDiskSampling } from './procedural/poissonDisk.js'; /** -<<<<<<< HEAD * Voronoi diagram helper returning polygonal cells for each site. * * Example file: examples/voronoi.ts */ export { computeVoronoiDiagram } from './procedural/voronoi.js'; -======= + +/** * Diamond-square fractal terrain generator. * * Example file: examples/diamondSquare.ts */ export { diamondSquare } from './procedural/diamondSquare.js'; ->>>>>>> c977c3c (feat: add diamond-square terrain generator) + +/** + * Lindenmayer system generator for procedural grammars. + * + * Example file: examples/lSystem.ts + */ +export { generateLSystem } from './procedural/lSystem.js'; // ============================================================================ // 🎯 SPATIAL & COLLISION diff --git a/src/procedural/lSystem.ts b/src/procedural/lSystem.ts new file mode 100644 index 0000000..26f6475 --- /dev/null +++ b/src/procedural/lSystem.ts @@ -0,0 +1,93 @@ +import { createLinearCongruentialGenerator } from '../util/prng.js'; + +export interface StochasticRule { + successor: string; + weight?: number; +} + +export type ProductionRule = string | ReadonlyArray; + +export type LSystemRules = Readonly>; + +export interface LSystemOptions { + axiom: string; + rules: LSystemRules; + iterations: number; + seed?: number; + trackHistory?: boolean; +} + +export interface LSystemResult { + result: string; + history: string[]; +} + +/** + * Generates rewritten strings using Lindenmayer systems (L-systems). + * Useful for: procedural foliage, fractal curves, grammar-based content. + * Performance: O(n * iterations) where n is current string length per step. + */ +export function generateLSystem({ + axiom, + rules, + iterations, + seed = Date.now(), + trackHistory = false, +}: LSystemOptions): LSystemResult { + if (iterations < 0 || !Number.isInteger(iterations)) { + throw new Error('iterations must be a non-negative integer.'); + } + if (!axiom) { + throw new Error('axiom must be a non-empty string.'); + } + + const random = createLinearCongruentialGenerator(seed); + let current = axiom; + const history: string[] = trackHistory ? [axiom] : []; + + for (let i = 0; i < iterations; i += 1) { + let next = ''; + for (const symbol of current) { + const production = rules[symbol]; + if (production === undefined) { + next += symbol; + continue; + } + if (typeof production === 'string') { + next += production; + } else if (Array.isArray(production) && production.length > 0) { + next += selectStochasticSuccessor(production, random); + } else { + next += symbol; + } + } + current = next; + if (trackHistory) { + history.push(current); + } + } + + return { + result: current, + history, + }; +} + +function selectStochasticSuccessor(rules: ReadonlyArray, random: () => number): string { + let totalWeight = 0; + for (const rule of rules) { + totalWeight += rule.weight ?? 1; + } + if (totalWeight <= 0) { + return rules[0]?.successor ?? ''; + } + const threshold = random() * totalWeight; + let cumulative = 0; + for (const rule of rules) { + cumulative += rule.weight ?? 1; + if (threshold <= cumulative) { + return rule.successor; + } + } + return rules[rules.length - 1]?.successor ?? ''; +} diff --git a/tests/index.test.ts b/tests/index.test.ts index 0ee4ffa..03db706 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -12,6 +12,7 @@ describe('package entry point', () => { expect(examples.procedural.poissonDiskSampling).toBe('examples/poissonDisk.ts'); expect(examples.procedural.computeVoronoiDiagram).toBe('examples/voronoi.ts'); expect(examples.procedural.diamondSquare).toBe('examples/diamondSquare.ts'); + expect(examples.procedural.generateLSystem).toBe('examples/lSystem.ts'); expect(examples.search.Trie).toBe('examples/search.ts'); expect(examples.pathfinding.buildNavMesh).toBe('examples/navMesh.ts'); }); @@ -54,6 +55,7 @@ describe('package entry point', () => { | 'poissonDiskSampling' | 'computeVoronoiDiagram' | 'diamondSquare' + | 'generateLSystem' >(); }); }); diff --git a/tests/lSystem.test.ts b/tests/lSystem.test.ts new file mode 100644 index 0000000..a3fdff3 --- /dev/null +++ b/tests/lSystem.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from 'vitest'; + +import { generateLSystem } from '../src/index.js'; + +describe('generateLSystem', () => { + it('expands deterministically for axiom and production rules', () => { + const { result, history } = generateLSystem({ + axiom: 'A', + iterations: 3, + rules: { + A: 'AB', + B: 'A', + }, + trackHistory: true, + }); + + expect(result).toBe('ABAAB'); + expect(history).toEqual(['A', 'AB', 'ABA', 'ABAAB']); + }); + + it('supports stochastic rules with deterministic seed', () => { + const rules = { + X: [ + { successor: 'XY', weight: 1 }, + { successor: 'XX', weight: 2 }, + ], + } as const; + + const { result: a } = generateLSystem({ axiom: 'X', iterations: 4, rules, seed: 123 }); + const { result: b } = generateLSystem({ axiom: 'X', iterations: 4, rules, seed: 123 }); + const { result: c } = generateLSystem({ axiom: 'X', iterations: 4, rules, seed: 456 }); + + expect(a).toEqual(b); + expect(c).not.toEqual(a); + }); +});