import { describe, expect, it } from 'vitest'; import { angleTo, clamp, clampLength, directionFromKeys, distance, inCircle, length, normalize, rotate, } from '../../app/static/js/logic/math.js'; import { createRng, pick, randFloat, randInt } from '../../app/static/js/logic/rng.js'; describe('math', () => { it('clamp begrenzt Werte', () => { expect(clamp(5, 0, 3)).toBe(3); expect(clamp(-1, 0, 3)).toBe(0); expect(clamp(2, 0, 3)).toBe(2); }); it('normalize lässt den Nullvektor unverändert', () => { expect(normalize({ x: 0, y: 0 })).toEqual({ x: 0, y: 0 }); expect(length(normalize({ x: 3, y: 4 }))).toBeCloseTo(1); }); it('clampLength kürzt nur zu lange Vektoren', () => { expect(length(clampLength({ x: 30, y: 40 }, 10))).toBeCloseTo(10); expect(clampLength({ x: 1, y: 1 }, 10)).toEqual({ x: 1, y: 1 }); }); it('rotate und angleTo passen zusammen', () => { const r = rotate({ x: 1, y: 0 }, Math.PI / 2); expect(r.x).toBeCloseTo(0); expect(r.y).toBeCloseTo(1); expect(angleTo({ x: 0, y: 0 }, { x: 0, y: 5 })).toBeCloseTo(Math.PI / 2); }); it('inCircle berücksichtigt die Ausdehnung des Objekts', () => { expect(inCircle({ x: 110, y: 0 }, { x: 0, y: 0 }, 100)).toBe(false); expect(inCircle({ x: 110, y: 0 }, { x: 0, y: 0 }, 100, 12)).toBe(true); expect(distance({ x: 0, y: 0 }, { x: 3, y: 4 })).toBe(5); }); it('directionFromKeys normalisiert Diagonalen (8-Wege-Bewegung)', () => { expect(directionFromKeys({ up: true, down: false, left: false, right: false })).toEqual({ x: 0, y: -1 }); const diag = directionFromKeys({ up: true, down: false, left: false, right: true }); expect(length(diag)).toBeCloseTo(1); expect(diag.x).toBeGreaterThan(0); expect(diag.y).toBeLessThan(0); expect(directionFromKeys({ up: true, down: true, left: true, right: true })).toEqual({ x: 0, y: 0 }); }); }); describe('rng', () => { it('ist mit gleichem Seed deterministisch und liegt in [0, 1)', () => { const a = createRng(123); const b = createRng(123); for (let i = 0; i < 1000; i += 1) { const value = a(); expect(value).toBe(b()); expect(value).toBeGreaterThanOrEqual(0); expect(value).toBeLessThan(1); } }); it('randInt deckt die Grenzen ab und bleibt im Intervall', () => { const rng = createRng(7); const seen = new Set(); for (let i = 0; i < 500; i += 1) { const n = randInt(rng, 1, 3); expect(n).toBeGreaterThanOrEqual(1); expect(n).toBeLessThanOrEqual(3); seen.add(n); } expect(seen).toEqual(new Set([1, 2, 3])); }); it('randFloat und pick verhalten sich korrekt', () => { const rng = createRng(9); const f = randFloat(rng, 5, 6); expect(f).toBeGreaterThanOrEqual(5); expect(f).toBeLessThan(6); expect(['a', 'b']).toContain(pick(rng, ['a', 'b'])); expect(() => pick(rng, [])).toThrow(); }); });