anvilsign in

collin/mahjong

master / src / ui / flick.test.ts
1import { describe, expect, it } from 'vitest';
2import { flickOf, type Sample } from './flick';
3
4/** A stroke of `n` points, each turned `turn` radians further round than the
5 * last, `step` px apart, one every `ms`. `turn` of 0 is a straight flick. */
6function stroke(n: number, step: number, turn: number, ms: number): Sample[] {
7 const out: Sample[] = [{ x: 0, y: 0, t: 0 }];
8 let a = 0;
9 for (let i = 1; i < n; i++) {
10 const p = out[i - 1];
11 out.push({ x: p.x + Math.cos(a) * step, y: p.y + Math.sin(a) * step, t: i * ms });
12 a += turn;
13 }
14 return out;
15}
16
17describe('reading a flick', () => {
18 it('reads the speed off the stroke, not off its last pair of points', () => {
19 // 20px every 10ms is 2000px/s, whatever the sampling happened to be.
20 const v = flickOf(stroke(6, 20, 0, 10));
21 expect(Math.hypot(v.vx, v.vy)).toBeCloseTo(2000, 0);
22 });
23
24 it('puts no turn on a straight flick, however fast it was made', () => {
25 expect(flickOf(stroke(6, 20, 0, 10)).spin).toBe(0);
26 expect(flickOf(stroke(6, 60, 0, 10)).spin).toBe(0);
27 });
28
29 it('puts a turn on one that curves, and the way it curved', () => {
30 const right = flickOf(stroke(6, 20, 0.25, 10)).spin;
31 const left = flickOf(stroke(6, 20, -0.25, 10)).spin;
32 expect(right).toBeGreaterThan(0.5);
33 expect(left).toBeCloseTo(-right, 6);
34 });
35
36 it('reads the same curve made faster as more turn, which is what a rate means', () => {
37 // The same shape, drawn in half the time. The old measure was the area
38 // between the two halves of the stroke and had no time in it at all, so a
39 // lazy curl and a hooked flick came out the same.
40 const slow = flickOf(stroke(6, 20, 0.25, 20)).spin;
41 const fast = flickOf(stroke(6, 20, 0.25, 10)).spin;
42 expect(fast).toBeCloseTo(slow * 2, 4);
43 });
44
45 it('gives up rather than guessing when there is nothing to read', () => {
46 expect(flickOf([])).toEqual({ vx: 0, vy: 0, spin: 0 });
47 expect(flickOf([{ x: 0, y: 0, t: 0 }])).toEqual({ vx: 0, vy: 0, spin: 0 });
48 // A press that never moved is not a curve, whatever the jitter says.
49 expect(flickOf(stroke(6, 1, 0.6, 10)).spin).toBe(0);
50 });
51});