import { describe, expect, test } from "vitest"; import { computeReachCircles, reachBound, REACH_CIRCLE_ID_PREFIX, } from "../src/map/reach-circles"; const CENTER = { x: 500, y: 500 }; describe("computeReachCircles", () => { test("no circles for a non-positive speed", () => { expect(computeReachCircles(CENTER, 0, 1000, 1000, "torus")).toEqual([]); expect(computeReachCircles(CENTER, -5, 1000, 1000, "torus")).toEqual([]); }); test("torus: a slow ship shows all three rings", () => { // bound = min(1000,1000)/2 = 500; speed 100 keeps every ring inside. const circles = computeReachCircles(CENTER, 100, 1000, 1000, "torus"); expect(circles.map((c) => c.radius)).toEqual([100, 200, 300]); expect(circles[0].id).toBe(REACH_CIRCLE_ID_PREFIX + 1); expect(circles[0].style.strokeColor).toBeDefined(); }); test("torus: a ship reaching the wrap midpoint shows one ring", () => { // speed 500 hits the bound on turn 1, so turn 2 is dropped. const circles = computeReachCircles(CENTER, 500, 1000, 1000, "torus"); expect(circles).toHaveLength(1); expect(circles[0].radius).toBe(500); }); test("torus: a mid-speed ship shows two rings", () => { // speed 300: ring 1 = 300 (< 500), ring 2 = 600; ring 3 dropped // because 2 × 300 = 600 ≥ 500. const circles = computeReachCircles(CENTER, 300, 1000, 1000, "torus"); expect(circles.map((c) => c.radius)).toEqual([300, 600]); }); test("no-wrap: the bound is the farthest corner", () => { // origin at a corner → farthest corner is the diagonal. expect(reachBound({ x: 0, y: 0 }, 1000, 1000, "no-wrap")).toBeCloseTo( Math.hypot(1000, 1000), 6, ); const circles = computeReachCircles( { x: 0, y: 0 }, 500, 1000, 1000, "no-wrap", ); // bound ≈ 1414, so all three rings fit. expect(circles.map((c) => c.radius)).toEqual([500, 1000, 1500]); }); });