Files
Battle-for-Tismo/tests/map_generator_test.js
T
2026-09-16 19:59:18 +02:00

120 lines
4.1 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { MapGenerator } from "../shared/map_generator.js";
import { MapTopology, key } from "../shared/hex.js";
import { MAP_CONFIG } from "../shared/data.js";
import { Random } from "../shared/rng.js";
function config(overrides = {}) {
return {
...MAP_CONFIG,
mapSize: { x: 32, y: 24 },
minCapitalLandmass: 1,
minCapitalDistance: 2,
...overrides,
};
}
function generate(cfg = config()) {
const topology = new MapTopology(cfg.mapSize, cfg.topology === "cylindrical");
const generator = new MapGenerator(cfg, topology);
generator.generate(cfg.terrainSeed);
return generator;
}
export class MapGeneratorTest extends TestCase {
test_generate_is_deterministic_for_a_seed() {
const a = generate();
const b = generate();
this.assertEqual(a.landCells, b.landCells);
this.assertEqual(Object.keys(a.tiles).length, Object.keys(b.tiles).length);
}
test_generate_marks_every_cell_as_land_or_sea() {
const cfg = config();
const generator = generate(cfg);
this.assertNotEmpty(generator.landCells);
this.assertSize(generator.tiles, cfg.mapSize.x * cfg.mapSize.y);
for (const coords of generator.landCells) {
this.assertEqual(generator.tiles[key(coords.x, coords.y)].terrainClass, "Land");
}
}
test_generate_records_pure_tile_data() {
const generator = generate();
for (const coords of generator.landCells) {
const tile = generator.tiles[key(coords.x, coords.y)];
this.assertHas(tile, "terrainClass");
this.assertHas(tile, "movementCostMultiplier");
this.assertHas(tile, "populationMultiplier");
this.assertHas(tile, "gdpMultiplier");
}
}
test_pick_capitals_returns_land_within_count() {
const generator = generate();
const capitals = generator.pickCapitals(3, new Random(1));
this.assertSize(capitals, 3);
for (const coords of capitals) {
this.assertTrue(
generator.landCells.some((c) => c.x === coords.x && c.y === coords.y),
`capital ${coords.x},${coords.y} is land`
);
}
}
test_pick_capitals_respects_distance() {
const cfg = config({ minCapitalDistance: 3 });
const generator = generate(cfg);
const capitals = generator.pickCapitals(2, new Random(1));
this.assertSize(capitals, 2);
const distance = generator.topology.tileDistance(capitals[0], capitals[1]);
this.assertGreaterOrEqual(distance, cfg.minCapitalDistance, "capitals kept apart");
}
test_pick_cities_includes_one_site_per_capital() {
const cfg = config({ citiesPerCiv: 3, citySpacing: 2 });
const generator = generate(cfg);
const capitals = generator.pickCapitals(2, new Random(1));
const sites = generator.pickCities(capitals, cfg.citiesPerCiv, cfg.citySpacing);
this.assertNotEmpty(sites);
const seen = new Set();
let capitalSites = 0;
for (const site of sites) {
if (site.isCapital) capitalSites += 1;
const k = key(site.coords.x, site.coords.y);
this.assertFalse(seen.has(k), `duplicate city at ${k}`);
seen.add(k);
}
this.assertEqual(capitalSites, capitals.length);
}
test_poles_are_ice() {
const cfg = config({ iceLatitude: 0.5 });
const generator = generate(cfg);
const half = cfg.mapSize.y / 2;
for (const k in generator.tiles) {
const i = k.indexOf(",");
const y = Number(k.slice(i + 1));
if (Math.abs(y) / half >= cfg.iceLatitude) {
this.assertEqual(generator.tiles[k].terrainType, "Ice", `tile ${k}`);
}
}
}
test_equator_is_not_ice() {
const generator = generate();
for (const k in generator.tiles) {
const i = k.indexOf(",");
const y = Number(k.slice(i + 1));
if (Math.abs(y) < 2) this.assertNotEqual(generator.tiles[k].terrainType, "Ice");
}
}
test_falloff_lowers_the_edges() {
const cfg = config({ falloffEnabled: true, falloffStart: 0, falloffStrength: 1 });
const generator = generate(cfg);
this.assertApprox(generator._applyFalloff({ x: 0, y: 0 }, 1.0, false), 1.0, 1e-9);
this.assertApprox(generator._applyFalloff({ x: 16, y: 12 }, 1.0, false), 0.0, 1e-9);
}
}