import { describe, expect, test } from "vitest" import { DRLGROOMTILE_GetTileCache } from "../src/game/wilderness.ts" import { Rng } from "../src/game/rng.ts" import type { Dt1, Dt1Tile } from "../src/formats/dt1.ts" function makeMockDt1(tiles: (Partial & { rarity?: number; Rarity?: number })[]): Dt1 { return { warnings: [], versionMajor: 7, versionMinor: 6, tiles: tiles.map(t => ({ direction: 0, height: -80, width: 160, type: t.type ?? 0, style: t.style ?? 0, sequence: t.sequence ?? 0, materialFlags: 0, roofHeight: 0, animated: t.animated ?? 0, rarityFrameIndex: t.rarityFrameIndex ?? 1, subTileFlags: [], minBlockY: 0, bitmapHeight: 80, blocks: [], ...t, })), } } describe("DRLGROOMTILE_GetTileCache deterministic seed (Issue #78)", () => { const dt1 = makeMockDt1([ { type: 0, style: 0, sequence: 0, rarityFrameIndex: 20 }, { type: 0, style: 0, sequence: 1, rarityFrameIndex: 30 }, { type: 0, style: 0, sequence: 2, rarityFrameIndex: 50 }, ]) describe("same seed produces identical result", () => { test("same integer seed produces identical tile selection across multiple invocations", () => { const query1 = { type: 0, seed: 12345 } const query2 = { type: 0, seed: 12345 } const res1 = DRLGROOMTILE_GetTileCache([dt1], 1, query1) const res2 = DRLGROOMTILE_GetTileCache([dt1], 1, query2) expect(res1).not.toBeNull() expect(res2).not.toBeNull() expect(res1).toEqual(res2) }) test("same coordinates and seed produce identical tile selection", () => { const resA = DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: 99999, x: 15, y: 27 }) const resB = DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: 99999, x: 15, y: 27 }) expect(resA).not.toBeNull() expect(resA).toEqual(resB) }) test("same direct fractional roll produces identical tile selection", () => { const resA = DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: 0.45 }) const resB = DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: 0.45 }) expect(resA).not.toBeNull() expect(resA).toEqual(resB) }) test("identical Rng seeds produce identical sequences of tile selections", () => { const rng1 = new Rng(88888) const rng2 = new Rng(88888) const results1 = Array.from({ length: 20 }, () => DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: rng1 })?.sequence, ) const results2 = Array.from({ length: 20 }, () => DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: rng2 })?.sequence, ) expect(results1).toEqual(results2) }) }) describe("different seeds produce varying selections over multiple runs", () => { test("varying integer seeds select different tiles across runs", () => { const seenSequences = new Set() for (let s = 0; s < 50; s += 1) { const res = DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: s * 1000 + 7 }) if (res !== null) { seenSequences.add(res.sequence) } } // All 3 candidate sequences (0, 1, 2) should be selected across 50 distinct seeds expect(seenSequences.size).toBe(3) expect(seenSequences.has(0)).toBe(true) expect(seenSequences.has(1)).toBe(true) expect(seenSequences.has(2)).toBe(true) }) test("varying coordinates with same seed select different tiles", () => { const seenSequences = new Set() for (let x = 0; x < 50; x += 1) { const res = DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: 12345, x, y: 0 }) if (res !== null) { seenSequences.add(res.sequence) } } expect(seenSequences.size).toBeGreaterThan(1) }) test("consecutive draws from a single Rng produce varying selections", () => { const rng = new Rng(42) const seenSequences = new Set() for (let i = 0; i < 50; i += 1) { const res = DRLGROOMTILE_GetTileCache([dt1], 1, { type: 0, seed: rng }) if (res !== null) { seenSequences.add(res.sequence) } } expect(seenSequences.size).toBe(3) }) }) })