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.
This commit is contained in:
104
tests/swipe_commit.sx
Normal file
104
tests/swipe_commit.sx
Normal file
@@ -0,0 +1,104 @@
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user