import { describe, it, expect } from 'vitest'; import biomeDataArray from '../src/data/biomes.json'; import { createSeededNoise, sampleNoise } from '../src/world/noise'; import { generateWorld } from '../src/world/generator'; import type { BiomeData } from '../src/world/types'; // Load the first biome — structural compatibility with BiomeData const biome = biomeDataArray[0] as BiomeData; // ─── Noise ────────────────────────────────────────────────────── describe('Seeded Noise', () => { it('is deterministic with same seed', () => { const n1 = createSeededNoise(42); const n2 = createSeededNoise(42); expect(n1(0.5, 0.5)).toBe(n2(0.5, 0.5)); }); it('produces different results with different seeds', () => { const n1 = createSeededNoise(42); const n2 = createSeededNoise(99); expect(n1(0.5, 0.5)).not.toBe(n2(0.5, 0.5)); }); it('normalizes to [0, 1] via sampleNoise', () => { const noise = createSeededNoise(42); for (let i = 0; i < 200; i++) { const val = sampleNoise(noise, i * 0.3, i * 0.7, 0.1); expect(val).toBeGreaterThanOrEqual(0); expect(val).toBeLessThanOrEqual(1); } }); it('varies across coordinates', () => { const noise = createSeededNoise(42); const values = new Set(); for (let i = 0; i < 50; i++) { values.add(sampleNoise(noise, i, 0, 0.1)); } // Should have significant variety (not all same value) expect(values.size).toBeGreaterThan(20); }); }); // ─── Biome Data ───────────────────────────────────────────────── describe('Biome Data', () => { it('has valid structure', () => { expect(biome.id).toBe('catalytic-wastes'); expect(biome.tileSize).toBe(32); expect(biome.mapWidth).toBe(80); expect(biome.mapHeight).toBe(80); }); it('has 8 tile types', () => { expect(biome.tiles).toHaveLength(8); }); it('tile IDs are sequential starting from 0', () => { biome.tiles.forEach((tile, index) => { expect(tile.id).toBe(index); }); }); it('has both walkable and non-walkable tiles', () => { const walkable = biome.tiles.filter(t => t.walkable); const blocked = biome.tiles.filter(t => !t.walkable); expect(walkable.length).toBeGreaterThan(0); expect(blocked.length).toBeGreaterThan(0); }); it('elevation rules cover full [0, 1] range', () => { const rules = biome.generation.elevationRules; expect(rules.length).toBeGreaterThan(0); // Last rule should cover up to 1.0 expect(rules[rules.length - 1].below).toBe(1); // Rules should be sorted ascending for (let i = 1; i < rules.length; i++) { expect(rules[i].below).toBeGreaterThan(rules[i - 1].below); } }); it('all elevation rule tileIds reference valid tiles', () => { const validIds = new Set(biome.tiles.map(t => t.id)); for (const rule of biome.generation.elevationRules) { expect(validIds.has(rule.tileId)).toBe(true); } }); }); // ─── World Generation ─────────────────────────────────────────── describe('World Generation', () => { it('generates grid with correct dimensions', () => { const world = generateWorld(biome, 42); expect(world.grid).toHaveLength(biome.mapHeight); for (const row of world.grid) { expect(row).toHaveLength(biome.mapWidth); } }); it('all tile IDs in grid are valid', () => { const world = generateWorld(biome, 42); const validIds = new Set(biome.tiles.map(t => t.id)); for (const row of world.grid) { for (const tileId of row) { expect(validIds.has(tileId)).toBe(true); } } }); it('is deterministic — same seed same map', () => { const w1 = generateWorld(biome, 42); const w2 = generateWorld(biome, 42); expect(w1.grid).toEqual(w2.grid); }); it('different seeds produce different maps', () => { const w1 = generateWorld(biome, 42); const w2 = generateWorld(biome, 99); expect(w1.grid).not.toEqual(w2.grid); }); it('stores seed and biome reference', () => { const world = generateWorld(biome, 12345); expect(world.seed).toBe(12345); expect(world.biome).toBe(biome); }); it('has diverse tile distribution (no single tile > 60%)', () => { const world = generateWorld(biome, 42); const counts = new Map(); for (const row of world.grid) { for (const tileId of row) { counts.set(tileId, (counts.get(tileId) ?? 0) + 1); } } const total = biome.mapWidth * biome.mapHeight; // At least 4 different tile types present expect(counts.size).toBeGreaterThanOrEqual(4); // No single type dominates for (const count of counts.values()) { expect(count / total).toBeLessThan(0.6); } }); it('generates acid pools (low elevation)', () => { const world = generateWorld(biome, 42); const acidId = biome.tiles.find(t => t.name === 'acid-pool')?.id; const hasAcid = world.grid.some(row => row.includes(acidId!)); expect(hasAcid).toBe(true); }); it('generates crystal formations (high elevation)', () => { const world = generateWorld(biome, 42); const crystalId = biome.tiles.find(t => t.name === 'crystal')?.id; const hasCrystals = world.grid.some(row => row.includes(crystalId!)); expect(hasCrystals).toBe(true); }); it('generates mineral veins (overlay on ground)', () => { const world = generateWorld(biome, 42); const mineralId = biome.tiles.find(t => t.name === 'mineral-vein')?.id; const hasMinerals = world.grid.some(row => row.includes(mineralId!)); expect(hasMinerals).toBe(true); }); it('generates geysers (overlay near acid)', () => { const world = generateWorld(biome, 42); const geyserId = biome.tiles.find(t => t.name === 'geyser')?.id; const hasGeysers = world.grid.some(row => row.includes(geyserId!)); expect(hasGeysers).toBe(true); }); it('produces unique map every seed (sample 5 seeds)', () => { const grids = [1, 2, 3, 4, 5].map(s => generateWorld(biome, s).grid); for (let i = 0; i < grids.length; i++) { for (let j = i + 1; j < grids.length; j++) { expect(grids[i]).not.toEqual(grids[j]); } } }); });