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_topology_type_width_and_period() { this.assertFalse(this.flat().isCylindrical()); this.assertApprox(this.flat().periodPixels(), 0, 1e-9); const cylinder = this.cylinder(); this.assertTrue(cylinder.isCylindrical()); this.assertEqual(cylinder.width, 10); this.assertApprox(cylinder.periodPixels(), COL_STEP * 10, 1e-9); } test_wrap_x_folds_only_on_a_cylinder() { const flatTopology = this.flat(); this.assertEqual(flatTopology.wrapX(25), 25); this.assertEqual(flatTopology.wrapCoords(25, -3), { x: 25, y: -3 }); 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_wrapped_delta_takes_the_short_route() { this.assertEqual(this.flat().wrappedDelta({ x: -5, y: 0 }, { x: 4, y: 0 }), { x: 9, y: 0 }); this.assertEqual(this.cylinder().wrappedDelta({ x: -5, y: 0 }, { x: 4, y: 0 }), { x: -1, y: 0 }); this.assertApprox(this.cylinder().tileDistance({ x: -5, y: 0 }, { x: 4, y: 0 }), 1.0, 1e-9); const topology = this.cylinder(); const delta = topology.pixelDelta({ x: 0, y: 0 }, { x: -4, y: 0 }); const expected = mapToLocal(-4, 0); this.assertApprox(delta.x, expected.x, 1e-9); this.assertApprox(delta.y, expected.y, 1e-9); } test_neighbours_are_six_adjacent_cells_that_wrap() { 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"]); 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); } const cylinder = this.cylinder(); for (const neighbour of cylinder.neighbours(-5, 0)) { this.assert(neighbour.x >= -5 && neighbour.x <= 4, `x ${neighbour.x} outside map`); } this.assertTrue( cylinder.neighbours(-5, 0).some((c) => c.x === 4), "the west neighbour of the seam wraps to the east edge" ); } test_key_and_parse_key_round_trip_and_odd_column_offset() { 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); } 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); } }