import { describe, expect, it } from 'vitest' import { hogTrimStartIndex, sampleTime, trimPathToStartAtHogLine, velocityToWeight, weightToVelocity, } from './game-helpers' import { SAMPLE_RATE_HZ } from './protocol' describe('trimPathToStartAtHogLine', () => { it('trims path at the first hog-line crossing and preserves theta', () => { // (x, y, theta) — time is derived from index after trim const path: [number, number, number][] = [ [0, 2, 0.1], [0, 20, 0.2], [0, 21.5, 0.3], [0, 30, 0.4], ] const trimmed = trimPathToStartAtHogLine(path) expect(trimmed[0][1]).toBe(20) expect(trimmed[0][2]).toBe(0.2) expect(trimmed[trimmed.length - 1][2]).toBe(0.4) expect(trimmed).toHaveLength(3) }) it('returns full path when hog line is never reached', () => { const path: [number, number, number][] = [ [0, 2, 0], [0, 10, 0.5], ] expect(trimPathToStartAtHogLine(path)).toEqual(path) }) }) describe('sampleTime', () => { it('is index / SAMPLE_RATE_HZ', () => { expect(sampleTime(0)).toBe(0) expect(sampleTime(SAMPLE_RATE_HZ)).toBe(1) expect(sampleTime(1)).toBeCloseTo(1 / SAMPLE_RATE_HZ) }) }) describe('hogTrimStartIndex', () => { it('returns index just before hog crossing', () => { const path: [number, number, number][] = [ [0, 2, 0], [0, 20, 0], [0, 21.5, 0], ] expect(hogTrimStartIndex(path)).toBe(1) }) }) describe('velocity ↔ weight', () => { it('maps endpoints correctly', () => { expect(velocityToWeight(3.0)).toBe(1) expect(velocityToWeight(6.45)).toBe(10) expect(weightToVelocity(1)).toBe(3.0) expect(weightToVelocity(10)).toBe(6.45) }) it('clamps out-of-range inputs', () => { expect(velocityToWeight(2.5)).toBe(1) expect(velocityToWeight(7.0)).toBe(10) expect(weightToVelocity(0)).toBe(3.0) expect(weightToVelocity(11)).toBe(6.45) }) })