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:
swipelab
2026-06-05 00:32:40 +03:00
parent ea0ba59a23
commit e5df37523f
7 changed files with 188 additions and 5 deletions

10
main.sx
View File

@@ -44,10 +44,15 @@ g_assets : *BoardAssets = null;
// per-frame rebuild; a tap hit-tests a cell and toggles this.
g_sel : *BoardSelection = null;
// In-progress touch drag (P5.2). Heap-allocated for the same reason: the press
// and release that bracket a swipe land on different per-frame BoardView values,
// so the drag start must persist between them.
g_drag : *DragInput = null;
// Rebuilt each frame inside the pipeline's arena; carries the current safe-area
// insets so the grid stays inside the notch / home-indicator region.
build_ui :: () -> View {
BoardView.{ board = g_board, assets = g_assets, sel = g_sel, safe = g_safe_insets }
BoardView.{ board = g_board, assets = g_assets, sel = g_sel, drag = g_drag, safe = g_safe_insets }
}
frame :: () {
@@ -144,6 +149,9 @@ main :: () -> void {
g_sel = xx context.allocator.alloc(size_of(BoardSelection));
g_sel.init();
g_drag = xx context.allocator.alloc(size_of(DragInput));
g_drag.init();
g_pipeline.set_body(closure(build_ui));
g_plat.run_frame_loop(closure(frame));