Files
m3te/tests/swipe_commit.sx
swipelab e5df37523f P5.2: swipe commits legal swap / reverts illegal (sx, iOS sim)
Wire touch input into the model in BoardView.handle_event. A press records
the drag start (new DragInput, heap-allocated so it survives the per-frame
BoardView rebuild between mouse_down and mouse_up); the release resolves the
gesture against the same layout it was drawn with. A swipe — start→end mapped
by swipe_intent to an adjacent-swap intent — is fed straight into
commit_swap: a legal swap applies, cascades (clear→collapse→refill), accrues
score and spends a move; an illegal one reverts, no move. A sub-threshold /
off-board drag carries no intent and falls back to the tap behaviour
(toggle/clear selection). The next frame re-renders board + HUD from the model.

Reuses swipe.sx + board_layout.sx + commit_swap unchanged — this is wiring,
not new legality/cascade logic.

tests/swipe_commit.sx (new golden) drives the full path on the seeded board
(SEED 1337): a rightward swipe (0,0)->(1,0) is illegal (two reds) and reverts
byte-for-byte with no score/move; (5,4)->(6,4) is legal, completes R,R,R on
row 4, awards 30, spends one move.

Sim evidence (iPhone 17, iOS 26.0): goldens/p5_swap_before.png (SCORE 0,
MOVES 30/30) and goldens/p5_swap_after.png (SCORE 30, MOVES 29/30) bracket a
real idb-injected swipe at (276,475)->(327,475) pt = cell (5,4)->(6,4); the
three reds clear and the board matches the model's resolved state.
2026-06-05 00:32:40 +03:00

105 lines
4.6 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.
// Swipe→commit wiring golden (P5.2): prove the full input-to-model path P5.2
// adds — a touch drag resolved by `swipe_intent` and fed straight into
// `commit_swap` — on the SAME seeded board the iOS app renders (SEED 1337).
// Feeds SYNTHETIC down/up screen positions built from a BoardLayout, resolves
// the swap intent, then commits it, asserting:
// - an ILLEGAL swipe ((0,0)->(1,0): two reds → no match) reverts: the board is
// byte-for-byte unchanged, score stays 0, and no move is spent;
// - a known LEGAL swipe ((5,4)->(6,4): brings R into (5,4), completing R,R,R
// across cols 3-5 of row 4) commits: the board changes, score accrues, and
// exactly one move is spent.
// No rendering, no model reach-around — it calls exactly what BoardView.handle_event
// calls. Links headless like tests/swipe_intent.sx; avoids tests/test.sx because
// its trace.sx pulls in a second `Frame` that collides with the UI one. 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";
#import "swipe.sx";
SEED :: 1337;
cell_center :: (lay: *BoardLayout, col: s64, row: s64) -> Point {
cf := lay.cell_frame(col, row);
Point.{ x = cf.mid_x(), y = cf.mid_y() }
}
boards_equal :: (x: *Board, y: *Board) -> bool {
for 0..BOARD_CELLS: (i) {
if !(x.cells[i] == y.cells[i]) { return false; }
}
true
}
main :: () -> s32 {
// 800×600, no safe inset → 600px square grid, cell 75, origin (100, 0). A
// 60px drag clears the cell*0.5 = 37.5px swipe threshold on the dominant axis.
lay : BoardLayout = ---;
lay.compute(Frame.make(0.0, 0.0, 800.0, 600.0), EdgeInsets.zero());
D : f32 = 60.0;
fails : s64 = 0;
// ── ILLEGAL swipe reverts ──────────────────────────────────────────────
// (0,0) and (1,0) are both red on the seed board, so swapping them forms no
// match. The rightward drag must resolve to exactly this pair, and
// commit_swap must reject it — board untouched, score 0, no move spent.
print("== illegal swipe reverts ==\n");
bi : Board = ---;
bi.init(SEED);
before : Board = bi;
out(board_dump(@bi));
a_il := cell_center(@lay, 0, 0);
if s := swipe_intent(@lay, a_il, Point.{ x = a_il.x + D, y = a_il.y }) {
print("intent ({},{})->({},{})\n", s.a.col, s.a.row, s.b.col, s.b.row);
if !(s.a.col == 0 and s.a.row == 0 and s.b.col == 1 and s.b.row == 0) { fails += 1; }
mv := commit_swap(@bi, s.a, s.b);
print("legal {} awarded {} score {} moves_made {} moves_remaining {}\n",
mv.legal, mv.cascade.awarded, bi.score, bi.moves_made, mv.moves_remaining);
if mv.legal { fails += 1; }
if !boards_equal(@before, @bi) { fails += 1; }
if bi.score != 0 { fails += 1; }
if bi.moves_made != 0 { fails += 1; }
if mv.moves_remaining != bi.move_limit { fails += 1; }
} else {
print("intent none\n");
fails += 1;
}
// ── LEGAL swipe commits ────────────────────────────────────────────────
// (5,4)->(6,4): the rightward swipe brings R into (5,4), completing R,R,R
// across cols 3-5 of row 4. commit_swap applies it, resolves the cascade
// (score accrues into Board.score) and spends one move; the board changes.
print("== legal swipe commits ==\n");
bl : Board = ---;
bl.init(SEED);
pre : Board = bl;
a_le := cell_center(@lay, 5, 4);
if s := swipe_intent(@lay, a_le, Point.{ x = a_le.x + D, y = a_le.y }) {
print("intent ({},{})->({},{})\n", s.a.col, s.a.row, s.b.col, s.b.row);
if !(s.a.col == 5 and s.a.row == 4 and s.b.col == 6 and s.b.row == 4) { fails += 1; }
mv := commit_swap(@bl, s.a, s.b);
print("legal {} depth {} awarded {} score {} moves_made {} moves_remaining {}\n",
mv.legal, mv.cascade.depth, mv.cascade.awarded, bl.score, bl.moves_made, mv.moves_remaining);
if !mv.legal { fails += 1; }
if boards_equal(@pre, @bl) { fails += 1; }
if !(bl.score > 0) { fails += 1; }
if bl.moves_made != 1 { fails += 1; }
if mv.moves_remaining != bl.move_limit - 1 { fails += 1; }
out("after:\n");
out(board_dump(@bl));
} else {
print("intent none\n");
fails += 1;
}
if fails == 0 {
print("ok: swipe reverts illegal, commits legal\n");
return 0;
}
print("FAIL: {} swipe-commit checks failed\n", fails);
return 1;
}