diff --git a/board.sx b/board.sx index 385d6a0..36b2ea1 100644 --- a/board.sx +++ b/board.sx @@ -155,8 +155,8 @@ Board :: struct { self.moves_made = 0; self.move_limit = DEFAULT_MOVE_LIMIT; self.target_score = DEFAULT_TARGET_SCORE; - for 0..BOARD_ROWS: (row) { - for 0..BOARD_COLS: (col) { + for 0..BOARD_ROWS (row) { + for 0..BOARD_COLS (col) { self.set(col, row, pick_gem(self, @self.rng, col, row)); } } @@ -167,7 +167,7 @@ Board :: struct { // upward. Pure given the board's already-placed prefix and the RNG state. pick_gem :: (board: *Board, rng: *Rng, col: s64, row: s64) -> Gem { forbidden : [GEM_COUNT]bool = ---; - for 0..GEM_COUNT: (t) { forbidden[t] = false; } + for 0..GEM_COUNT (t) { forbidden[t] = false; } // Two same gems immediately to the left → a third of that type matches. if col >= 2 { @@ -185,11 +185,11 @@ pick_gem :: (board: *Board, rng: *Rng, col: s64, row: s64) -> Gem { } allowed := 0; - for 0..GEM_COUNT: (t) { if !forbidden[t] { allowed += 1; } } + for 0..GEM_COUNT (t) { if !forbidden[t] { allowed += 1; } } // Pick the k-th still-allowed type; single RNG draw, always terminates. k := rng.next_range(allowed); - for 0..GEM_COUNT: (t) { + for 0..GEM_COUNT (t) { if !forbidden[t] { if k == 0 { return cast(Gem) t; } k -= 1; @@ -203,9 +203,9 @@ pick_gem :: (board: *Board, rng: *Rng, col: s64, row: s64) -> Gem { board_dump :: (self: *Board) -> string { line_w := BOARD_COLS + 1; // 8 gem chars + newline buf := cstring(BOARD_ROWS * line_w); - for 0..BOARD_ROWS: (row) { + for 0..BOARD_ROWS (row) { base := row * line_w; - for 0..BOARD_COLS: (col) { + for 0..BOARD_COLS (col) { buf[base + col] = gem_char(self.at(col, row)); } buf[base + BOARD_COLS] = 10; // '\n' @@ -229,7 +229,7 @@ MatchMask :: struct { count :: (self: *MatchMask) -> s64 { n : s64 = 0; - for 0..BOARD_CELLS: (i) { if self.cells[i] { n += 1; } } + for 0..BOARD_CELLS (i) { if self.cells[i] { n += 1; } } n } } @@ -238,7 +238,7 @@ MatchMask :: struct { // is the constant coordinate (the row for a horizontal span, the column for a // vertical one) and the span covers `start..end` of the moving coordinate. mark_run :: (m: *MatchMask, vertical: bool, fixed: s64, start: s64, end: s64) { - for start..end: (i) { + for start..end (i) { if vertical { m.cells[Board.idx(fixed, i)] = true; } else { @@ -259,10 +259,10 @@ mark_run :: (m: *MatchMask, vertical: bool, fixed: s64, start: s64, end: s64) { // break runs of real gems, since a hole differs from every gem type. find_matches :: (b: *Board) -> MatchMask { m : MatchMask = ---; - for 0..BOARD_CELLS: (i) { m.cells[i] = false; } + for 0..BOARD_CELLS (i) { m.cells[i] = false; } // Horizontal: walk each row left-to-right in maximal same-type spans. - for 0..BOARD_ROWS: (row) { + for 0..BOARD_ROWS (row) { col := 0; while col < BOARD_COLS { g := b.at(col, row); @@ -276,7 +276,7 @@ find_matches :: (b: *Board) -> MatchMask { } // Vertical: walk each column top-to-bottom in maximal same-type spans. - for 0..BOARD_COLS: (col) { + for 0..BOARD_COLS (col) { row := 0; while row < BOARD_ROWS { g := b.at(col, row); @@ -299,9 +299,9 @@ find_matches :: (b: *Board) -> MatchMask { dump_matches :: (b: *Board, m: *MatchMask) -> string { line_w := BOARD_COLS + 1; // 8 cells + newline buf := cstring(BOARD_ROWS * line_w); - for 0..BOARD_ROWS: (row) { + for 0..BOARD_ROWS (row) { base := row * line_w; - for 0..BOARD_COLS: (col) { + for 0..BOARD_COLS (col) { if m.at(col, row) { buf[base + col] = gem_char(b.at(col, row)); } else { @@ -371,8 +371,8 @@ Swap :: struct { // the snapshot can depend on it. legal_swaps :: (board: *Board) -> List(Swap) { result := List(Swap).{}; - for 0..BOARD_ROWS: (row) { - for 0..BOARD_COLS: (col) { + for 0..BOARD_ROWS (row) { + for 0..BOARD_COLS (col) { here := Cell.{ col = col, row = row }; if col + 1 < BOARD_COLS { right := Cell.{ col = col + 1, row = row }; @@ -397,7 +397,7 @@ legal_swaps :: (board: *Board) -> List(Swap) { // as just "0 legal swaps", which reads unambiguously. Suitable for snapshotting. dump_swaps :: (swaps: *List(Swap)) -> string { result := format("{} legal swaps\n", swaps.len); - for 0..swaps.len: (i) { + for 0..swaps.len (i) { s := swaps.items[i]; result = concat(result, format("({},{})-({},{})\n", s.a.col, s.a.row, s.b.col, s.b.row)); } @@ -415,7 +415,7 @@ dump_swaps :: (swaps: *List(Swap)) -> string { // `true` per shared cell) clear as one set with no double-counting. clear_cells :: (board: *Board, mask: *MatchMask) -> s64 { cleared : s64 = 0; - for 0..BOARD_CELLS: (i) { + for 0..BOARD_CELLS (i) { if mask.cells[i] { board.cells[i] = .empty; cleared += 1; @@ -449,7 +449,7 @@ clear_matches :: (board: *Board) -> s64 { // this to know when gravity has stopped. collapse :: (board: *Board) -> bool { moved := false; - for 0..BOARD_COLS: (col) { + for 0..BOARD_COLS (col) { // Pack this column's gems toward the bottom: scan it bottom-to-top and // write each gem at the falling cursor `w`, which also descends from the // bottom. A gem whose source row differs from `w` actually fell. `w` @@ -492,8 +492,8 @@ collapse :: (board: *Board) -> bool { refill :: (board: *Board) -> s64 { rng := @board.rng; filled : s64 = 0; - for 0..BOARD_ROWS: (row) { - for 0..BOARD_COLS: (col) { + for 0..BOARD_ROWS (row) { + for 0..BOARD_COLS (col) { if board.at(col, row) == .empty { board.set(col, row, cast(Gem) rng.next_range(GEM_COUNT)); filled += 1; @@ -628,7 +628,7 @@ run_score :: (len: s64) -> s64 { find_runs :: (b: *Board) -> List(Run) { runs := List(Run).{}; - for 0..BOARD_ROWS: (row) { + for 0..BOARD_ROWS (row) { col := 0; while col < BOARD_COLS { g := b.at(col, row); @@ -643,7 +643,7 @@ find_runs :: (b: *Board) -> List(Run) { } } - for 0..BOARD_COLS: (col) { + for 0..BOARD_COLS (col) { row := 0; while row < BOARD_ROWS { g := b.at(col, row); @@ -669,7 +669,7 @@ find_runs :: (b: *Board) -> List(Run) { score_round :: (board: *Board) -> s64 { runs := find_runs(board); total : s64 = 0; - for 0..runs.len: (i) { + for 0..runs.len (i) { total += run_score(runs.items[i].len); } total @@ -724,7 +724,7 @@ SpecialCounts :: struct { count_specials :: (board: *Board) -> SpecialCounts { runs := find_runs(board); counts := SpecialCounts.{ len4 = 0, len5_plus = 0 }; - for 0..runs.len: (i) { + for 0..runs.len (i) { len := runs.items[i].len; if len == 4 { counts.len4 += 1; @@ -741,7 +741,7 @@ count_specials :: (board: *Board) -> SpecialCounts { // "0 runs". Suitable for snapshotting. dump_runs :: (runs: *List(Run)) -> string { result := format("{} runs\n", runs.len); - for 0..runs.len: (i) { + for 0..runs.len (i) { r := runs.items[i]; axis := if r.vertical then "V" else "H"; result = concat(result, format("{} len {} at fixed {} start {}\n", axis, r.len, r.fixed, r.start)); @@ -829,8 +829,8 @@ level_status :: (board: *Board) -> Status { // a throwaway list each call. The trial swaps inside `swap_legal` are reverted, // so the board is left unchanged. has_legal_swap :: (board: *Board) -> bool { - for 0..BOARD_ROWS: (row) { - for 0..BOARD_COLS: (col) { + for 0..BOARD_ROWS (row) { + for 0..BOARD_COLS (col) { here := Cell.{ col = col, row = row }; if col + 1 < BOARD_COLS { right := Cell.{ col = col + 1, row = row }; diff --git a/board_anim.sx b/board_anim.sx index 9d73d9b..9dc536f 100644 --- a/board_anim.sx +++ b/board_anim.sx @@ -163,7 +163,7 @@ ClearDiag :: struct { lo: s64; hi: s64; } clear_diag_span :: (m: *MatchMask) -> ClearDiag { lo : s64 = (BOARD_COLS - 1) + (BOARD_ROWS - 1) + 1; hi : s64 = -1; - for 0..BOARD_CELLS: (i) { + for 0..BOARD_CELLS (i) { if m.cells[i] { d := (i % BOARD_COLS) + (i / BOARD_COLS); if d < lo { lo = d; } @@ -277,7 +277,7 @@ plan_and_commit :: (board: *Board, a: Cell, b: Cell) -> AnimMove { // came from source row `r`. The rows left above the survivors (0..w) are // refilled, so they drop in from above: a dest row `j` there starts at // `j - n_refill`, i.e. stacked just off the top edge. - for 0..BOARD_COLS: (col) { + for 0..BOARD_COLS (col) { w := BOARD_ROWS - 1; r := BOARD_ROWS - 1; while r >= 0 { @@ -362,7 +362,7 @@ BoardAnim :: struct { return AnimPhase.{ kind = .swap, round = 0, t = e / SWAP_ANIM_DUR }; } e -= SWAP_ANIM_DUR; - for 0..self.move.rounds.len: (k) { + for 0..self.move.rounds.len (k) { if e < CLEAR_ANIM_DUR { return AnimPhase.{ kind = .clear, round = k, t = e / CLEAR_ANIM_DUR }; } diff --git a/board_fx.sx b/board_fx.sx index 11fac9e..9f76674 100644 --- a/board_fx.sx +++ b/board_fx.sx @@ -123,7 +123,7 @@ BoardFxAssets :: struct { loaded: bool; init :: (self: *BoardFxAssets) { - for 0..GEM_COUNT: (t) { self.tex[t] = 0; } + for 0..GEM_COUNT (t) { self.tex[t] = 0; } self.loaded = false; } @@ -144,7 +144,7 @@ BoardFxAssets :: struct { // (sx codegen), so the per-pixel tint loop only ASSIGNS pre-declared vars. i : s64 = 0; o : s64 = 0; - for 0..GEM_COUNT: (t) { + for 0..GEM_COUNT (t) { col := fx_tint(t); i = 0; while i < n { @@ -219,7 +219,7 @@ BoardFx :: struct { // Whole-move depth boost: a deeper cascade makes every burst bigger from // its first round, escalating in lockstep with the cascade SFX cue. depth_boost := FX_BURST_DEPTH * cast(f32) fx_combo_level(mv.rounds.len); - for 0..mv.rounds.len: (k) { + for 0..mv.rounds.len (k) { rd := @mv.rounds.items[k]; t0 := SWAP_ANIM_DUR + cast(f32) k * (CLEAR_ANIM_DUR + FALL_ANIM_DUR); extra := depth_boost + FX_BURST_COMBO * cast(f32) min(k, 2); @@ -227,7 +227,7 @@ BoardFx :: struct { // bursts ripple in lockstep with the staggered pops (P18.2) instead of // one simultaneous flash. The round's audio cue still fires once at t0. span := clear_diag_span(@rd.matched); - for 0..BOARD_CELLS: (idx) { + for 0..BOARD_CELLS (idx) { if rd.matched.cells[idx] { g := rd.before[idx]; if g != .empty { @@ -253,7 +253,7 @@ BoardFx :: struct { sc : s64 = 0; sr : s64 = 0; cnt : s64 = 0; - for 0..BOARD_CELLS: (idx) { + for 0..BOARD_CELLS (idx) { if rd0.matched.cells[idx] { sc += idx % BOARD_COLS; sr += idx / BOARD_COLS; diff --git a/board_view.sx b/board_view.sx index ed5d4be..0417bdf 100644 --- a/board_view.sx +++ b/board_view.sx @@ -357,8 +357,8 @@ BoardView :: struct { // Settled-board gems: one sprite per non-empty cell, drawn with its live // per-gem animation pose. Used whenever no move is animating. render_gems :: (self: *BoardView, ctx: *RenderContext, dim: f32) { - for 0..BOARD_ROWS: (row) { - for 0..BOARD_COLS: (col) { + for 0..BOARD_ROWS (row) { + for 0..BOARD_COLS (col) { g := self.board.at(col, row); if g != .empty { pose := self.gem_pose_at(col, row); @@ -431,7 +431,7 @@ BoardView :: struct { // (which resumes the same back-dated stamp). tick() normally clears // `active` before this is reached. last := mv.rounds.len - 1; - for 0..BOARD_CELLS: (i) { + for 0..BOARD_CELLS (i) { g := mv.final[i]; if g != .empty { sq := self.rest_squash(i, last, e); @@ -452,7 +452,7 @@ BoardView :: struct { ai := Board.idx(mv.a.col, mv.a.row); bi := Board.idx(mv.b.col, mv.b.row); - for 0..BOARD_CELLS: (i) { + for 0..BOARD_CELLS (i) { if i == ai or i == bi { continue; } g := mv.pre[i]; if g != .empty { @@ -495,7 +495,7 @@ BoardView :: struct { // satisfying pop, composing with the particle burst); the rest hold position. render_clear :: (self: *BoardView, ctx: *RenderContext, rd: *AnimRound, k: s64, e: f32, dim: f32, t: f32) { span := clear_diag_span(@rd.matched); - for 0..BOARD_CELLS: (i) { + for 0..BOARD_CELLS (i) { g := rd.before[i]; if g == .empty { continue; } col := i % BOARD_COLS; @@ -532,7 +532,7 @@ BoardView :: struct { cs * cast(f32) BOARD_COLS, cs * cast(f32) BOARD_ROWS ); ctx.push_clip(grid); - for 0..self.fx.particles.len: (i) { + for 0..self.fx.particles.len (i) { p := self.fx.particles.items[i]; lt := (p.age - p.delay) / p.life; env := fx_pop_env(lt); @@ -556,7 +556,7 @@ BoardView :: struct { render_fx_popups :: (self: *BoardView, ctx: *RenderContext) { if self.fx == null or self.fx.popups.len == 0 { return; } cs := self.layout.cell_size; - for 0..self.fx.popups.len: (i) { + for 0..self.fx.popups.len (i) { q := self.fx.popups.items[i]; lt := (q.age - q.delay) / q.life; if lt >= 0.0 { @@ -594,7 +594,7 @@ BoardView :: struct { // guarantees every column reaches 1 by t==1, so each gem lands exactly on its // cell and the seam to the next round / settled board stays invisible. render_fall :: (self: *BoardView, ctx: *RenderContext, rd: *AnimRound, k: s64, e: f32, dim: f32, t: f32) { - for 0..BOARD_CELLS: (i) { + for 0..BOARD_CELLS (i) { g := rd.after[i]; if g == .empty { continue; } col := i % BOARD_COLS; @@ -731,8 +731,8 @@ impl View for BoardView { gem_inset := self.layout.cell_size * (1.0 - GEM_FILL_FRAC) * 0.5; gem_dim := self.layout.cell_size * GEM_FILL_FRAC; if self.assets.cell_tex != 0 { - for 0..BOARD_ROWS: (row) { - for 0..BOARD_COLS: (col) { + for 0..BOARD_ROWS (row) { + for 0..BOARD_COLS (col) { ctx.add_image(self.layout.cell_frame(col, row), self.assets.cell_tex); } } diff --git a/gem_anim.sx b/gem_anim.sx index 8484a9c..5c22774 100644 --- a/gem_anim.sx +++ b/gem_anim.sx @@ -132,7 +132,7 @@ GemMotion :: struct { // its resting pose instead of replaying the prior move's landing wobble; the // idle clock keeps running, so the always-on idle simply resumes from rest. reset_landings :: (self: *GemMotion) { - for 0..BOARD_CELLS: (i) { self.land_at[i] = -1000.0; } + for 0..BOARD_CELLS (i) { self.land_at[i] = -1000.0; } } stamp_land :: (self: *GemMotion, i: s64) { diff --git a/main.sx b/main.sx index 8f938be..1aa7cde 100644 --- a/main.sx +++ b/main.sx @@ -183,8 +183,8 @@ parse_s64 :: (s: string) -> s64 { // trial swaps inside `swap_legal` are reverted, so the board is left unchanged. illegal_swaps :: (board: *Board) -> List(Swap) { result := List(Swap).{}; - for 0..BOARD_ROWS: (row) { - for 0..BOARD_COLS: (col) { + for 0..BOARD_ROWS (row) { + for 0..BOARD_COLS (col) { here := Cell.{ col = col, row = row }; if col + 1 < BOARD_COLS { right := Cell.{ col = col + 1, row = row }; @@ -222,7 +222,7 @@ frame :: () { g_pipeline.resize(fc.viewport_w, fc.viewport_h); } - for g_plat.poll_events(): (*ev) { + for g_plat.poll_events() (*ev) { inline if OS != .ios { if ev == { case .key_up: (e) { @@ -277,7 +277,7 @@ frame :: () { mv := @g_anim.move; total := g_anim.total(); last := mv.rounds.len - 1; - for 0..BOARD_CELLS: (i) { + for 0..BOARD_CELLS (i) { m := delivering_round(mv, i, last); if m >= 0 { col := i % BOARD_COLS; diff --git a/tests/anim_plan.sx b/tests/anim_plan.sx index 7f622b3..97a2e4a 100644 --- a/tests/anim_plan.sx +++ b/tests/anim_plan.sx @@ -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; } } } diff --git a/tests/banner_layout.sx b/tests/banner_layout.sx index 4c8a2e1..b568b9a 100644 --- a/tests/banner_layout.sx +++ b/tests/banner_layout.sx @@ -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"; diff --git a/tests/board_init.sx b/tests/board_init.sx index e67349d..9b4b829 100644 --- a/tests/board_init.sx +++ b/tests/board_init.sx @@ -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; } } diff --git a/tests/cascade.sx b/tests/cascade.sx index 85eab42..6177758 100644 --- a/tests/cascade.sx +++ b/tests/cascade.sx @@ -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; } } } diff --git a/tests/cascade_cue.sx b/tests/cascade_cue.sx index f558d68..853e179 100644 --- a/tests/cascade_cue.sx +++ b/tests/cascade_cue.sx @@ -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. diff --git a/tests/cascade_rounds.sx b/tests/cascade_rounds.sx index ac5d717..decf440 100644 --- a/tests/cascade_rounds.sx +++ b/tests/cascade_rounds.sx @@ -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; diff --git a/tests/clear.sx b/tests/clear.sx index d9c65d4..b229035 100644 --- a/tests/clear.sx +++ b/tests/clear.sx @@ -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 { diff --git a/tests/collapse.sx b/tests/collapse.sx index 3166574..934d7e1 100644 --- a/tests/collapse.sx +++ b/tests/collapse.sx @@ -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 { diff --git a/tests/combo.sx b/tests/combo.sx index ab08176..f902dcc 100644 --- a/tests/combo.sx +++ b/tests/combo.sx @@ -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])); } } diff --git a/tests/easing.sx b/tests/easing.sx index 99c67de..3289556 100644 --- a/tests/easing.sx +++ b/tests/easing.sx @@ -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 diff --git a/tests/fx_combo.sx b/tests/fx_combo.sx index 56de877..7ec64df 100644 --- a/tests/fx_combo.sx +++ b/tests/fx_combo.sx @@ -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; } diff --git a/tests/gem_pose.sx b/tests/gem_pose.sx index c731852..70db336 100644 --- a/tests/gem_pose.sx +++ b/tests/gem_pose.sx @@ -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; } diff --git a/tests/hit_test.sx b/tests/hit_test.sx index f4c586c..b2887df 100644 --- a/tests/hit_test.sx +++ b/tests/hit_test.sx @@ -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) { diff --git a/tests/level.sx b/tests/level.sx index fcdb0aa..fc1a4aa 100644 --- a/tests/level.sx +++ b/tests/level.sx @@ -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 } diff --git a/tests/match_detect.sx b/tests/match_detect.sx index e3dd996..573a4d8 100644 --- a/tests/match_detect.sx +++ b/tests/match_detect.sx @@ -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])); } } diff --git a/tests/refill.sx b/tests/refill.sx index a64ca92..de3022c 100644 --- a/tests/refill.sx +++ b/tests/refill.sx @@ -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)"); diff --git a/tests/score.sx b/tests/score.sx index a3626a2..0c956da 100644 --- a/tests/score.sx +++ b/tests/score.sx @@ -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])); } } diff --git a/tests/swap_legality.sx b/tests/swap_legality.sx index 88813f8..5548031 100644 --- a/tests/swap_legality.sx +++ b/tests/swap_legality.sx @@ -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 diff --git a/tests/swipe_commit.sx b/tests/swipe_commit.sx index 908e151..19154d3 100644 --- a/tests/swipe_commit.sx +++ b/tests/swipe_commit.sx @@ -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 diff --git a/tests/swipe_intent.sx b/tests/swipe_intent.sx index 018e7d2..f83f423 100644 --- a/tests/swipe_intent.sx +++ b/tests/swipe_intent.sx @@ -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"; diff --git a/tests/swipe_reshuffle.sx b/tests/swipe_reshuffle.sx index 850c443..0834634 100644 --- a/tests/swipe_reshuffle.sx +++ b/tests/swipe_reshuffle.sx @@ -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])); } } diff --git a/tests/turn.sx b/tests/turn.sx index 1d6af04..0db53ee 100644 --- a/tests/turn.sx +++ b/tests/turn.sx @@ -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 }