Files
m3te/tests/hit_test.sx
swipelab 9ed98c73d2 P4.4: selection highlight + score/moves HUD (sx, iOS sim)
Tap a gem to select it: BoardView hit-tests the touch to a grid cell and
draws a bright rim + translucent fill over it; tapping the same cell clears
the selection, tapping another moves it, tapping off-board clears it.
Selection only — no swap (that's P5). The HUD renders the live score and
remaining moves (out of the move limit) in the Lato font on a translucent
card above the grid.

The touch→cell geometry is factored into a pure BoardLayout (no GL/stb
imports) that BoardView composes and P5 will reuse for swap endpoints.
tests/hit_test.sx locks point_to_cell as the exact inverse of cell_frame
(every cell center round-trips; off-board taps reject) — headless because
BoardLayout pulls no C imports. goldens/p4_hud.png captures the scene after
a real idb tap at (201,437)pt: the HUD plus a yellow selection rim on the
red gem at cell (col 4, row 3).
2026-06-05 00:00:48 +03:00

69 lines
3.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Hit-test golden (P4.4): lock the touch→cell mapping `BoardLayout.point_to_cell`
// as the exact inverse of `cell_frame`. The two are written independently — one
// multiplies a cell index by cell_size, the other divides a point by cell_size
// and truncates — so round-tripping every cell center back to its own cell is a
// real check, not a tautology. BoardView and P5's swap input both reuse this
// mapping, so a drift here would silently send taps/swaps to the wrong cell.
//
// Imports BoardLayout (no GL/stb), not BoardView, so it links headless. It also
// avoids tests/test.sx, whose modules/process.sx → modules/trace.sx pulls in a
// second `Frame` struct that collides with the UI `Frame`. Failure is signalled
// via a non-zero exit code (the runner checks exit code AND stdout).
#import "modules/std.sx";
#import "board.sx";
#import "board_layout.sx";
main :: () -> s32 {
// 800×600 with no safe inset → a 600px square grid, cell 75, centered: the
// grid origin lands at (100, 0). Integer math keeps the dump deterministic.
lay : BoardLayout = ---;
lay.compute(Frame.make(0.0, 0.0, 800.0, 600.0), EdgeInsets.zero());
print("grid origin ({},{}) cell {}\n",
cast(s64) lay.origin.x, cast(s64) lay.origin.y, cast(s64) lay.cell_size);
fails : s64 = 0;
// Every cell center must map back to its own cell.
hits : s64 = 0;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_COLS: (col) {
cf := lay.cell_frame(col, row);
center := Point.{ x = cf.mid_x(), y = cf.mid_y() };
if h := lay.point_to_cell(center) {
if h.col == col and h.row == row { hits += 1; }
}
}
}
if hits != BOARD_CELLS { fails += 1; }
print("ok: {}/{} cell centers round-trip\n", hits, BOARD_CELLS);
// A cell's top-left corner belongs to that cell (the leading edge is
// inclusive), so corner-of-(3,5) resolves to (3,5).
corner := Point.{ x = lay.origin.x + 3.0 * lay.cell_size, y = lay.origin.y + 5.0 * lay.cell_size };
corner_col : s64 = -1;
corner_row : s64 = -1;
if h := lay.point_to_cell(corner) { corner_col = h.col; corner_row = h.row; }
if corner_col != 3 or corner_row != 5 { fails += 1; }
print("corner maps to ({},{})\n", corner_col, corner_row);
// Off-board taps reject (null): left of, above, and right of the grid. None
// should resolve to a cell, so the on-board count must stay 0.
off_left := Point.{ x = lay.origin.x - 5.0, y = lay.origin.y + 10.0 };
off_above := Point.{ x = lay.origin.x + 10.0, y = lay.origin.y - 5.0 };
off_right := Point.{ x = lay.origin.x + 8.0 * lay.cell_size + 1.0, y = lay.origin.y + 10.0 };
on_board : s64 = 0;
if h := lay.point_to_cell(off_left) { on_board += 1; print("off_left hit ({},{})\n", h.col, h.row); }
if h := lay.point_to_cell(off_above) { on_board += 1; print("off_above hit ({},{})\n", h.col, h.row); }
if h := lay.point_to_cell(off_right) { on_board += 1; print("off_right hit ({},{})\n", h.col, h.row); }
if on_board != 0 { fails += 1; }
print("ok: {} off-board taps resolved to a cell\n", on_board);
if fails == 0 {
print("ok: hit-test mapping is the inverse of the layout\n");
return 0;
}
print("FAIL: {} hit-test checks failed\n", fails);
return 1;
}