Files
SpaceWanderer/lib/game/world.test.ts

80 lines
3.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { generateRing, generateStartRegion, makeName, mulberry32 } from './world'
describe('generateStartRegion', () => {
const region = generateStartRegion(mulberry32(42))
it('produces a starting system plus six neighbours', () => {
expect(region.neighbors).toHaveLength(6)
expect(region.start.x).toBe(50)
expect(region.start.y).toBe(50)
})
it('gives every system a unique name and in-bounds coordinates', () => {
const all = [region.start, ...region.neighbors]
const names = all.map((s) => s.name)
expect(new Set(names).size).toBe(names.length)
for (const s of all) {
expect(s.x).toBeGreaterThanOrEqual(0)
expect(s.x).toBeLessThanOrEqual(100)
expect(s.y).toBeGreaterThanOrEqual(0)
expect(s.y).toBeLessThanOrEqual(100)
}
})
it('connects the start to every neighbour and closes the ring cycle', () => {
const n = region.neighbors.length
// anchor↔each member (n edges) + ring cycle (n edges)
expect(region.edges).toHaveLength(n * 2)
for (let i = 0; i < n; i++) {
expect(region.edges).toContainEqual([0, i + 1])
expect(region.edges).toContainEqual([i + 1, ((i + 1) % n) + 1])
}
// every edge endpoint is a valid index into [start, ...neighbors]
for (const [a, b] of region.edges) {
expect(a).toBeGreaterThanOrEqual(0)
expect(a).toBeLessThan(n + 1)
expect(b).toBeGreaterThanOrEqual(0)
expect(b).toBeLessThan(n + 1)
}
})
it('is deterministic under a fixed seed and differs across seeds', () => {
const again = generateStartRegion(mulberry32(42))
expect(again).toEqual(region)
const other = generateStartRegion(mulberry32(43))
expect(other.start.name !== region.start.name || other.neighbors[0].name !== region.neighbors[0].name).toBe(true)
})
})
describe('generateRing (expansion)', () => {
it('adds four systems spaced away from the anchor and existing positions', () => {
const takenNames = new Set(['Kepler Drift'])
const takenPositions = [{ name: 'Kepler Drift', x: 50, y: 50 }]
const ring = generateRing(mulberry32(7), 50, 50, takenNames, takenPositions)
expect(ring.systems).toHaveLength(4)
const ringNames = ring.systems.map((s) => s.name)
for (const s of ring.systems) {
expect(Math.hypot(s.x - 50, s.y - 50)).toBeGreaterThanOrEqual(16)
expect(s.name).not.toBe('Kepler Drift') // never reuses a pre-taken name
}
expect(new Set(ringNames).size).toBe(4) // and makeName claimed them into the set
for (const n of ringNames) expect(takenNames.has(n)).toBe(true)
expect(ring.edges).toHaveLength(8) // anchor↔each + cycle
for (const [a, b] of ring.edges) {
expect(a).toBeGreaterThanOrEqual(0)
expect(a).toBeLessThan(5)
expect(b).toBeGreaterThanOrEqual(0)
expect(b).toBeLessThan(5)
}
})
it('never reuses a taken name', () => {
const rng = mulberry32(1)
const taken = new Set<string>()
for (let i = 0; i < 40; i++) makeName(rng, taken)
expect(taken.size).toBe(40)
})
})