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

106 lines
3.6 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import { MapTopology, mapToLocal, key, parseKey, COL_STEP, HEX_H } from "../shared/hex.js";
export class HexTest extends TestCase {
flat() {
return new MapTopology({ x: 10, y: 10 }, false);
}
cylinder() {
return new MapTopology({ x: 10, y: 10 }, true);
}
test_flat_reports_flat() {
this.assertFalse(this.flat().isCylindrical());
}
test_cylindrical_reports_type_and_width() {
const topology = this.cylinder();
this.assertTrue(topology.isCylindrical());
this.assertEqual(topology.width, 10);
}
test_flat_wrap_is_identity() {
const topology = this.flat();
this.assertEqual(topology.wrapX(25), 25);
this.assertEqual(topology.wrapCoords(25, -3), { x: 25, y: -3 });
}
test_cylindrical_wrap_folds_x_into_range() {
const topology = this.cylinder();
// Origin is -5, so the valid x range is -5..4.
this.assertEqual(topology.wrapX(-5), -5);
this.assertEqual(topology.wrapX(4), 4);
this.assertEqual(topology.wrapX(5), -5);
this.assertEqual(topology.wrapX(-6), 4);
}
test_flat_delta_is_plain_difference() {
this.assertEqual(this.flat().wrappedDelta({ x: -5, y: 0 }, { x: 4, y: 0 }), { x: 9, y: 0 });
}
test_cylindrical_delta_takes_short_route() {
this.assertEqual(this.cylinder().wrappedDelta({ x: -5, y: 0 }, { x: 4, y: 0 }), { x: -1, y: 0 });
}
test_tile_distance_uses_wrap() {
this.assertApprox(this.cylinder().tileDistance({ x: -5, y: 0 }, { x: 4, y: 0 }), 1.0, 1e-9);
}
test_neighbours_are_the_six_flat_top_cells() {
const topology = this.flat();
const neighbours = topology.neighbours(0, 0).map((c) => key(c.x, c.y)).sort();
this.assertEqual(neighbours, ["-1,-1", "-1,0", "0,-1", "0,1", "1,-1", "1,0"]);
}
test_neighbours_are_adjacent_in_pixel_space() {
const topology = this.flat();
const centre = mapToLocal(0, 0);
for (const neighbour of topology.neighbours(0, 0)) {
const delta = topology.pixelDelta({ x: 0, y: 0 }, neighbour);
const distance = Math.hypot(delta.x, delta.y);
this.assert(distance > 0 && distance <= HEX_H + 1e-9, `distance ${distance}`);
const local = mapToLocal(neighbour.x, neighbour.y);
this.assertApprox(local.x - centre.x, delta.x, 1e-9);
this.assertApprox(local.y - centre.y, delta.y, 1e-9);
}
}
test_neighbours_wrap_at_the_seam() {
const topology = this.cylinder();
for (const neighbour of topology.neighbours(-5, 0)) {
this.assert(neighbour.x >= -5 && neighbour.x <= 4, `x ${neighbour.x} outside map`);
}
const west = topology.neighbours(-5, 0).some((c) => c.x === 4);
this.assertTrue(west, "the west neighbour of the seam wraps to the east edge");
}
test_pixel_delta_matches_map_to_local() {
const topology = this.cylinder();
const from = { x: 0, y: 0 };
const to = { x: -4, y: 0 };
const delta = topology.pixelDelta(from, to);
const expected = mapToLocal(-4, 0);
this.assertApprox(delta.x, expected.x, 1e-9);
this.assertApprox(delta.y, expected.y, 1e-9);
}
test_period_pixels_matches_map_width() {
this.assertApprox(this.flat().periodPixels(), 0, 1e-9);
this.assertApprox(this.cylinder().periodPixels(), COL_STEP * 10, 1e-9);
}
test_key_and_parse_key_round_trip() {
for (const coords of [{ x: 0, y: 0 }, { x: 3, y: -4 }, { x: -12, y: 7 }]) {
this.assertEqual(parseKey(key(coords.x, coords.y)), coords);
}
}
test_odd_columns_are_pushed_down() {
const even = mapToLocal(0, 0);
const odd = mapToLocal(1, 0);
this.assertApprox(odd.x - even.x, COL_STEP, 1e-9);
this.assertApprox(odd.y - even.y, HEX_H / 2, 1e-9);
}
}