migrate to the new for-loop syntax

Drop the ':' before captures (for xs (x) / for 0..n (i)); the index
capture becomes the trailing open range (for xs, 0.. (x, i)). 136
headers across 26 files, mechanical.

Five headless tests (banner_layout, hit_test, swipe_commit,
swipe_intent, swipe_reshuffle) also gain a direct
#import "modules/ui/types.sx" — they named Point/Frame through a
transitive import, which bare visibility no longer permits.

Gates: sx build --target ios-sim main.sx links; tools/run_tests.sh
23/23.
This commit is contained in:
swipelab
2026-06-10 20:39:59 +03:00
parent 5a0627bb7c
commit a7b41ccbca
28 changed files with 141 additions and 136 deletions

View File

@@ -24,7 +24,7 @@
SEED :: 1337;
boards_equal :: (x: *Board, y: *Board) -> bool {
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if !(x.cells[i] == y.cells[i]) { return false; }
}
true
@@ -61,7 +61,7 @@ main :: () -> s32 {
// move.final equals the model board.
final_eq := true;
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if !(move.final[i] == bm.cells[i]) { final_eq = false; }
}
if !final_eq { fails += 1; }
@@ -74,21 +74,21 @@ main :: () -> s32 {
ai := Board.idx(a.col, a.row);
bi := Board.idx(b.col, b.row);
r0 := @move.rounds.items[0];
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
expect : Gem = move.pre[i];
if i == ai { expect = move.pre[bi]; }
else if i == bi { expect = move.pre[ai]; }
if !(r0.before[i] == expect) { contiguous = false; }
}
for 1..move.rounds.len: (k) {
for 1..move.rounds.len (k) {
prev := @move.rounds.items[k - 1];
cur := @move.rounds.items[k];
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if !(cur.before[i] == prev.after[i]) { contiguous = false; }
}
}
last := @move.rounds.items[move.rounds.len - 1];
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if !(last.after[i] == move.final[i]) { contiguous = false; }
}
}

View File

@@ -13,6 +13,7 @@
// shape and rationale as tests/hit_test.sx. Failure is signalled via a non-zero
// exit code (the runner checks exit code AND stdout).
#import "modules/std.sx";
#import "modules/ui/types.sx";
#import "board.sx";
#import "board_layout.sx";

View File

@@ -12,14 +12,14 @@ SEED :: 1337;
// independently of the placement logic, so it's a real check, not a tautology.
count_three_runs :: (b: *Board) -> s32 {
runs : s32 = 0;
for 0..BOARD_ROWS: (row) {
for 0..(BOARD_COLS - 2): (col) {
for 0..BOARD_ROWS (row) {
for 0..(BOARD_COLS - 2) (col) {
g := b.at(col, row);
if g == b.at(col + 1, row) and g == b.at(col + 2, row) { runs += 1; }
}
}
for 0..(BOARD_ROWS - 2): (row) {
for 0..BOARD_COLS: (col) {
for 0..(BOARD_ROWS - 2) (row) {
for 0..BOARD_COLS (col) {
g := b.at(col, row);
if g == b.at(col, row + 1) and g == b.at(col, row + 2) { runs += 1; }
}

View File

@@ -24,7 +24,7 @@ EXPECTED_DEPTH :: 2;
// board can be written as a human-readable grid. The hole glyph maps to `.empty`.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -34,9 +34,9 @@ char_to_gem :: (c: u8) -> Gem {
// The RNG is left unseeded — callers seed it before resolving.
load_board :: (rows: []string) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}
@@ -44,7 +44,7 @@ load_board :: (rows: []string) -> Board {
}
boards_equal :: (a: *Board, b: *Board) -> bool {
for 0..BOARD_CELLS: (i) { if a.cells[i] != b.cells[i] { return false; } }
for 0..BOARD_CELLS (i) { if a.cells[i] != b.cells[i] { return false; } }
true
}
@@ -120,7 +120,7 @@ main :: () -> s32 {
t.expect(c.depth == depth, "cascade: resolve depth matches manual loop");
same_counts := c.cleared.len == counts.len;
if same_counts {
for 0..counts.len: (i) {
for 0..counts.len (i) {
if c.cleared.items[i] != counts.items[i] { same_counts = false; }
}
}

View File

@@ -15,7 +15,7 @@ main :: () -> s32 {
// middle are visible: depths 0,1 pin to the first cue; depths >= 5 pin to
// the last; 2,3,4 step up one cue at a time.
prev : s64 = -1;
for 0..10: (depth) {
for 0..10 (depth) {
idx := cascade_cue_index(depth);
print("depth {} -> idx {} ({})\n", depth, idx, cascade_cue_name(idx));
// The mapping must never step down as depth grows.

View File

@@ -57,7 +57,7 @@ main :: () -> s32 {
// Deep chain: the cue tail clamps at combo5 for round >= 5 (cascade_cue_index).
print("-- deep-chain cue clamp --\n");
for 1..8: (r) { print("round {} -> {}\n", r, cascade_cue_name(cascade_cue_index(r))); }
for 1..8 (r) { print("round {} -> {}\n", r, cascade_cue_name(cascade_cue_index(r))); }
print("ok: one ascending combo cue per cascade round, clamped at combo5\n");
return 0;

View File

@@ -16,7 +16,7 @@ t :: #import "test.sx";
// clear) for the holes-never-match regression.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -26,9 +26,9 @@ char_to_gem :: (c: u8) -> Gem {
// characters).
load_board :: (rows: []string) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}
@@ -53,7 +53,7 @@ scene :: (name: string, rows: []string, want_cleared: s64) {
cleared_holes := true; // every matched cell is now a hole
others_intact := true; // every other cell is byte-identical
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if m.cells[i] {
if !(b.cells[i] == .empty) { cleared_holes = false; }
} else {

View File

@@ -18,7 +18,7 @@ t :: #import "test.sx";
// maps to `.empty`, so a board can be hand-written with holes in any position.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -27,9 +27,9 @@ char_to_gem :: (c: u8) -> Gem {
// Load an 8x8 board from `rows` (top row first, each exactly BOARD_COLS chars).
load_board :: (rows: []string) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}
@@ -42,15 +42,15 @@ load_board :: (rows: []string) -> Board {
// them a hole. This single check covers holes-bubble-to-top, gems-settle-to-
// bottom, order-preservation, and the all-holes / no-holes edge columns at once.
check_collapsed :: (orig: *Board, b: *Board) -> bool {
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
gems : [BOARD_ROWS]Gem = ---;
n := 0;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
g := orig.at(col, row);
if g != .empty { gems[n] = g; n += 1; }
}
boundary := BOARD_ROWS - n; // first row that must hold a gem
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
if row < boundary {
if b.at(col, row) != .empty { return false; }
} else {

View File

@@ -23,7 +23,7 @@ t :: #import "test.sx";
// be written as a human-readable grid. The hole glyph maps to `.empty`.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -33,9 +33,9 @@ char_to_gem :: (c: u8) -> Gem {
// seeded RNG, running score zeroed so `board.score` ends equal to the payout.
load_board :: (rows: []string, seed: s64) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}

View File

@@ -51,7 +51,7 @@ main :: () -> s32 {
p_io := ease_in_out_cubic(0.0);
p_oc := ease_out_cubic(0.0);
p_iq := ease_in_quad(0.0);
for 1..21: (i) {
for 1..21 (i) {
t := cast(f32) i / 20.0;
v_in := ease_in_cubic(t); if v_in < p_in - 0.000001 { mono_in = false; } p_in = v_in;
v_io := ease_in_out_cubic(t); if v_io < p_io - 0.000001 { mono_io = false; } p_io = v_io;
@@ -72,7 +72,7 @@ main :: () -> s32 {
back_mx := ease_out_back(0.0); back_mn := ease_out_back(0.0);
spr_mx := spring(0.0); spr_mn := spring(0.0);
spr_wobble := false;
for 1..21: (i) {
for 1..21 (i) {
t := cast(f32) i / 20.0;
b := ease_out_back(t);
if b > back_mx { back_mx = b; }
@@ -98,7 +98,7 @@ main :: () -> s32 {
// squash (positive) and a stretch (negative) lobe, and stays bounded.
print("== squash envelope bounded ==\n");
sq_mx : f32 = 0.0; sq_mn : f32 = 0.0; sq_moves := false;
for 0..21: (i) {
for 0..21 (i) {
t := cast(f32) i / 20.0;
s := squash_envelope(t);
if s > sq_mx { sq_mx = s; }
@@ -121,7 +121,7 @@ main :: () -> s32 {
print("== illegal-swap bounce ==\n");
bb_ends := bad_swap_bounce(0.0) == 0.0 and bad_swap_bounce(1.0) == 0.0;
bb_mx : f32 = 0.0; bb_mx_t : f32 = 0.0; bb_mn : f32 = 0.0;
for 0..101: (i) {
for 0..101 (i) {
t := cast(f32) i / 100.0;
v := bad_swap_bounce(t);
if v > bb_mx { bb_mx = v; bb_mx_t = t; }
@@ -151,18 +151,18 @@ main :: () -> s32 {
// starts later), the opposite of a flat lockstep row sharing one progress.
print("== fall stagger bounded ==\n");
stg_t0 := true; stg_t1 := true;
for 0..BOARD_COLS: (c) {
for 0..BOARD_COLS (c) {
if fall_stagger_t(0.0, c) != 0.0 { stg_t0 = false; }
if fall_stagger_t(1.0, c) != 1.0 { stg_t1 = false; }
}
stg_cascade := true;
for 1..BOARD_COLS: (c) {
for 1..BOARD_COLS (c) {
if !(fall_stagger_t(0.5, c) < fall_stagger_t(0.5, c - 1)) { stg_cascade = false; }
}
stg_mono := true;
for 0..BOARD_COLS: (c) {
for 0..BOARD_COLS (c) {
pp := fall_stagger_t(0.0, c);
for 1..21: (i) {
for 1..21 (i) {
tt := cast(f32) i / 20.0;
vv := fall_stagger_t(tt, c);
if vv < pp - 0.000001 { stg_mono = false; }
@@ -190,14 +190,14 @@ main :: () -> s32 {
lf_last := approx(fall_landing_frac(BOARD_COLS - 1), 1.0);
lf_mono := true;
lf_seam := true;
for 0..BOARD_COLS: (c) {
for 0..BOARD_COLS (c) {
if c >= 1 and !(fall_landing_frac(c) > fall_landing_frac(c - 1)) { lf_mono = false; }
lf := fall_landing_frac(c);
if !approx(fall_stagger_t(lf, c), 1.0) { lf_seam = false; } // landed at lf
if fall_stagger_t(lf - 0.05, c) >= 1.0 { lf_seam = false; } // still in air just before
}
rlt_col_mono := true;
for 1..BOARD_COLS: (c) {
for 1..BOARD_COLS (c) {
if !(round_land_time(0, c) > round_land_time(0, c - 1)) { rlt_col_mono = false; }
}
rlt_round_after := round_land_time(1, 0) > round_land_time(0, BOARD_COLS - 1);
@@ -222,22 +222,22 @@ main :: () -> s32 {
// gem 0..1 by diagonal across the round (lowest-diagonal = 0, the first to pop).
print("== clear ripple bounded ==\n");
rip_t0 := true; rip_t1 := true;
for 0..6: (j) {
for 0..6 (j) {
u := cast(f32) j / 5.0;
if clear_ripple_t(0.0, u) != 0.0 { rip_t0 = false; }
if clear_ripple_t(1.0, u) != 1.0 { rip_t1 = false; }
}
rip_ripple := true;
for 1..6: (j) {
for 1..6 (j) {
u := cast(f32) j / 5.0;
up := cast(f32) (j - 1) / 5.0;
if !(clear_ripple_t(0.5, u) < clear_ripple_t(0.5, up)) { rip_ripple = false; }
}
rip_mono := true;
for 0..6: (j) {
for 0..6 (j) {
u := cast(f32) j / 5.0;
pp := clear_ripple_t(0.0, u);
for 1..21: (i) {
for 1..21 (i) {
tt := cast(f32) i / 20.0;
vv := clear_ripple_t(tt, u);
if vv < pp - 0.000001 { rip_mono = false; }
@@ -245,7 +245,7 @@ main :: () -> s32 {
}
}
mm : MatchMask = ---;
for 0..BOARD_CELLS: (i) { mm.cells[i] = false; }
for 0..BOARD_CELLS (i) { mm.cells[i] = false; }
mm.cells[Board.idx(5, 0)] = true; // diagonal 5 — first to pop
mm.cells[Board.idx(5, 1)] = true; // diagonal 6
mm.cells[Board.idx(5, 2)] = true; // diagonal 7 — last to pop

View File

@@ -21,7 +21,7 @@ main :: () -> s32 {
expect_level : [10]s64 = .{ 0, 0, 1, 2, 3, 4, 4, 4, 4, 4 };
prev : s64 = -1;
for 0..10: (depth) {
for 0..10 (depth) {
lvl := fx_combo_level(depth);
font := fx_popup_font(depth);
combo := depth > 1;
@@ -45,7 +45,7 @@ main :: () -> s32 {
// larger and the font never shrinks as the cascade deepens.
if fx_popup_font(1) != FX_POPUP_FONT { print("FAIL: single-clear popup not plain font\n"); return 1; }
pf : f32 = 0.0;
for 2..10: (depth) {
for 2..10 (depth) {
f := fx_popup_font(depth);
if f <= FX_POPUP_FONT { print("FAIL: combo popup not larger than plain at depth {}\n", depth); return 1; }
if depth > 2 and f < pf { print("FAIL: popup font shrank at depth {}\n", depth); return 1; }

View File

@@ -24,8 +24,8 @@ main :: () -> s32 {
// 1. t==0 idle pose is EXACTLY rest for every cell (the determinism invariant).
print("== idle t=0 is rest for all cells ==\n");
rest_ok := true;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_COLS: (col) {
for 0..BOARD_ROWS (row) {
for 0..BOARD_COLS (col) {
p := idle_pose(0.0, col, row);
if !(p.scale_x == 1.0 and p.scale_y == 1.0 and p.dx == 0.0 and p.dy == 0.0) {
rest_ok = false;
@@ -39,8 +39,8 @@ main :: () -> s32 {
print("== idle mid-phase deforms, bounded ==\n");
moved := false;
bounded := true;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_COLS: (col) {
for 0..BOARD_ROWS (row) {
for 0..BOARD_COLS (col) {
p := idle_pose(0.6, col, row);
if fabs(p.scale_x - 1.0) > 0.0005 { moved = true; }
if fabs(p.scale_x - 1.0) > 0.05 { bounded = false; }
@@ -82,7 +82,7 @@ main :: () -> s32 {
c_peak := clear_pop_scale(0.30) > 1.1;
c_collapse := true;
pc := clear_pop_scale(CLEAR_POP_RISE);
for 1..21: (i) {
for 1..21 (i) {
tt := CLEAR_POP_RISE + (1.0 - CLEAR_POP_RISE) * cast(f32) i / 20.0;
vv := clear_pop_scale(tt);
if vv > pc + 0.000001 { c_collapse = false; }

View File

@@ -10,6 +10,7 @@
// 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 "modules/ui/types.sx";
#import "board.sx";
#import "board_layout.sx";
@@ -26,8 +27,8 @@ main :: () -> s32 {
// Every cell center must map back to its own cell.
hits : s64 = 0;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_COLS: (col) {
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) {

View File

@@ -25,7 +25,7 @@ RESHUFFLE_SEED :: 1337;
// be written as a human-readable grid. The hole glyph maps to `.empty`.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -36,9 +36,9 @@ char_to_gem :: (c: u8) -> Gem {
// the per-level goal set.
load_board :: (rows: []string, seed: s64, move_limit: s64, target_score: s64) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}
@@ -51,7 +51,7 @@ load_board :: (rows: []string, seed: s64, move_limit: s64, target_score: s64) ->
}
boards_equal :: (a: *Board, b: *Board) -> bool {
for 0..BOARD_CELLS: (i) { if a.cells[i] != b.cells[i] { return false; } }
for 0..BOARD_CELLS (i) { if a.cells[i] != b.cells[i] { return false; } }
true
}

View File

@@ -11,7 +11,7 @@ t :: #import "test.sx";
// Inverse of `gem_char`: map a gem character back to its Gem so each board can
// be written as a human-readable grid of GEM_CHARS.
char_to_gem :: (c: u8) -> Gem {
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -22,9 +22,9 @@ char_to_gem :: (c: u8) -> Gem {
// assert the matched-cell count.
scene :: (name: string, rows: []string, want_count: s64) {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}

View File

@@ -22,7 +22,7 @@ SEED :: 1337;
// board can be written as a human-readable grid. The hole glyph maps to `.empty`.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -32,9 +32,9 @@ char_to_gem :: (c: u8) -> Gem {
// The RNG is left unseeded — callers seed it before drawing.
load_board :: (rows: []string) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}
@@ -43,12 +43,12 @@ load_board :: (rows: []string) -> Board {
count_empties :: (b: *Board) -> s64 {
n : s64 = 0;
for 0..BOARD_CELLS: (i) { if b.cells[i] == .empty { n += 1; } }
for 0..BOARD_CELLS (i) { if b.cells[i] == .empty { n += 1; } }
n
}
boards_equal :: (a: *Board, b: *Board) -> bool {
for 0..BOARD_CELLS: (i) { if a.cells[i] != b.cells[i] { return false; } }
for 0..BOARD_CELLS (i) { if a.cells[i] != b.cells[i] { return false; } }
true
}
@@ -101,7 +101,7 @@ main :: () -> s32 {
distinct := false;
have_first := false;
first : Gem = .empty;
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if pre.cells[i] == .empty {
want := cast(Gem) v.next_range(GEM_COUNT);
if b.cells[i] != want { stream_ok = false; }
@@ -125,17 +125,17 @@ main :: () -> s32 {
holes_n := 0;
hole_idx : [BOARD_CELLS]s64 = ---;
fill1 : [BOARD_CELLS]Gem = ---;
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if pre.cells[i] == .empty {
hole_idx[holes_n] = i;
fill1[holes_n] = b.cells[i];
holes_n += 1;
}
}
for 0..holes_n: (k) { b.cells[hole_idx[k]] = .empty; }
for 0..holes_n (k) { b.cells[hole_idx[k]] = .empty; }
refill(@b);
differs := false;
for 0..holes_n: (k) {
for 0..holes_n (k) {
if b.cells[hole_idx[k]] != fill1[k] { differs = true; }
}
t.expect(differs, "refill: a second refill of the same holes draws new gems (RNG threads, no reseed)");

View File

@@ -20,7 +20,7 @@ t :: #import "test.sx";
// be written as a human-readable grid. The hole glyph maps to `.empty`.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -30,9 +30,9 @@ char_to_gem :: (c: u8) -> Gem {
// with the running score zeroed so the accumulation check starts from a known base.
load_board :: (rows: []string) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}

View File

@@ -16,7 +16,7 @@ SEED :: 1337;
// Inverse of `gem_char`: map a gem character back to its Gem so each board can
// be written as a human-readable grid of GEM_CHARS.
char_to_gem :: (c: u8) -> Gem {
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -26,9 +26,9 @@ char_to_gem :: (c: u8) -> Gem {
// characters).
load_board :: (rows: []string) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}
@@ -38,7 +38,7 @@ load_board :: (rows: []string) -> Board {
// Whole-board equality, cell by cell — used to prove a trial swap leaves the
// board untouched.
boards_equal :: (x: *Board, y: *Board) -> bool {
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if !(x.cells[i] == y.cells[i]) { return false; }
}
true

View File

@@ -13,6 +13,7 @@
// 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 "modules/ui/types.sx";
#import "board.sx";
#import "board_layout.sx";
#import "swipe.sx";
@@ -25,7 +26,7 @@ cell_center :: (lay: *BoardLayout, col: s64, row: s64) -> Point {
}
boards_equal :: (x: *Board, y: *Board) -> bool {
for 0..BOARD_CELLS: (i) {
for 0..BOARD_CELLS (i) {
if !(x.cells[i] == y.cells[i]) { return false; }
}
true

View File

@@ -9,6 +9,7 @@
// clears it; a 10px drag does not. Failure is signalled via a non-zero exit code
// (the runner checks exit code AND stdout).
#import "modules/std.sx";
#import "modules/ui/types.sx";
#import "board.sx";
#import "board_layout.sx";
#import "swipe.sx";

View File

@@ -16,6 +16,7 @@
// avoids tests/test.sx (its trace.sx pulls in a second `Frame` that collides with
// the UI one). Failure is a non-zero exit code (the runner checks exit + stdout).
#import "modules/std.sx";
#import "modules/ui/types.sx";
#import "board.sx";
#import "board_anim.sx";
#import "board_layout.sx";
@@ -27,7 +28,7 @@ SEED :: 1337;
// board can be written as a human-readable grid (mirrors tests/level.sx).
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -37,9 +38,9 @@ char_to_gem :: (c: u8) -> Gem {
// counters reset to a fresh game, and the per-level goal set.
load_board :: (rows: []string, seed: s64, move_limit: s64, target_score: s64) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}

View File

@@ -28,7 +28,7 @@ LIMIT :: 5;
// be written as a human-readable grid. The hole glyph maps to `.empty`.
char_to_gem :: (c: u8) -> Gem {
if c == EMPTY_CHAR { return .empty; }
for 0..GEM_COUNT: (i) {
for 0..GEM_COUNT (i) {
if GEM_CHARS[i] == c { return cast(Gem) i; }
}
.red
@@ -39,9 +39,9 @@ char_to_gem :: (c: u8) -> Gem {
// (no moves made, the given move budget).
load_board :: (rows: []string, seed: s64, move_limit: s64) -> Board {
b : Board = ---;
for 0..BOARD_ROWS: (row) {
for 0..BOARD_ROWS (row) {
line := rows[row];
for 0..BOARD_COLS: (col) {
for 0..BOARD_COLS (col) {
b.set(col, row, char_to_gem(line[col]));
}
}
@@ -53,7 +53,7 @@ load_board :: (rows: []string, seed: s64, move_limit: s64) -> Board {
}
boards_equal :: (a: *Board, b: *Board) -> bool {
for 0..BOARD_CELLS: (i) { if a.cells[i] != b.cells[i] { return false; } }
for 0..BOARD_CELLS (i) { if a.cells[i] != b.cells[i] { return false; } }
true
}