P2.1: clear matched cells (pure sx)
Add the first resolution-pipeline step to the headless board model.
- Introduce an `empty` hole sentinel on the Gem enum (ordinal 6, outside
GEM_COUNT so the RNG/pick_gem never draw it). board_dump renders holes as
EMPTY_CHAR ('.') via a single branch in gem_char, leaving boards without
holes byte-identical to before (existing goldens unchanged).
- clear_cells(board, mask): set every matched cell to `.empty`, leave all
others untouched, return the count cleared.
- clear_matches(board): detect+clear in one call; returns 0 (board unchanged)
when there are no matches.
No gravity or refill yet (P2.2 / P2.3).
tests/clear.sx applies detect->clear to hand-crafted boards (single
horizontal/vertical runs, disjoint runs, an overlapping L/T whose shared cell
clears once, and a no-match checkerboard), snapshots before/after, and asserts
matched cells became holes, non-matched cells are unchanged, and the cleared
count is exact. Locked as tests/expected/clear.{stdout,exit}.
This commit is contained in:
46
board.sx
46
board.sx
@@ -8,8 +8,10 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
// ── Gem ──────────────────────────────────────────────────────────────────
|
||||
// Six distinct gem types. The enum's ordinal (0..5) IS the gem index, so it
|
||||
// casts cleanly to/from the integers the RNG and the textual dump work in.
|
||||
// Six distinct gem types plus an `empty` hole sentinel. The ordinal of a real
|
||||
// gem (0..5) IS its gem index, so it casts cleanly to/from the integers the RNG
|
||||
// and the textual dump work in; `empty` (ordinal 6) sits outside that range and
|
||||
// is never drawn by the RNG.
|
||||
GEM_COUNT :: 6;
|
||||
|
||||
Gem :: enum {
|
||||
@@ -19,13 +21,24 @@ Gem :: enum {
|
||||
green;
|
||||
blue;
|
||||
purple;
|
||||
// A hole: a cell with no gem, left behind when a match is cleared (P2.1).
|
||||
// Distinct from all six gem types and never produced by init/pick_gem
|
||||
// (which only draw ordinals 0..GEM_COUNT), so gravity/refill (P2.2/P2.3) can
|
||||
// test a cell for `== .empty` to find holes. Outside GEM_CHARS, so it dumps
|
||||
// via the dedicated EMPTY_CHAR rather than the gem alphabet.
|
||||
empty;
|
||||
}
|
||||
|
||||
// One stable character per gem type, indexed by ordinal — the alphabet the
|
||||
// board dump (and its golden) is written in.
|
||||
GEM_CHARS :: "ROYGBP";
|
||||
|
||||
// Hole glyph for the board dump: an empty cell renders as this instead of a gem
|
||||
// character. Distinct from every gem in GEM_CHARS.
|
||||
EMPTY_CHAR :: 46; // '.'
|
||||
|
||||
gem_char :: (g: Gem) -> u8 {
|
||||
if g == .empty { return EMPTY_CHAR; }
|
||||
GEM_CHARS[cast(s64) g]
|
||||
}
|
||||
|
||||
@@ -332,3 +345,32 @@ dump_swaps :: (swaps: *List(Swap)) -> string {
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// ── Clear (P2.1) ─────────────────────────────────────────────────────────────
|
||||
// First step of the resolution pipeline: turn matched cells into holes. No
|
||||
// gravity or refill here (P2.2 / P2.3) — clearing only writes `.empty` into the
|
||||
// matched cells and leaves every other cell exactly as it was.
|
||||
|
||||
// Set every cell flagged in `mask` to a hole, leaving all unflagged cells
|
||||
// unchanged. Returns the number of cells cleared. `mask` is the matched-cell SET
|
||||
// from find_matches, so overlapping L/T shapes (already unioned into a single
|
||||
// `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) {
|
||||
if mask.cells[i] {
|
||||
board.cells[i] = .empty;
|
||||
cleared += 1;
|
||||
}
|
||||
}
|
||||
cleared
|
||||
}
|
||||
|
||||
// Detect matches on `board` and clear them in one step. Returns the number of
|
||||
// cells cleared — 0 when there are no matches, in which case the board is left
|
||||
// unchanged. The count drives later cascade/scoring (P2.2+): a non-zero result
|
||||
// means the board changed and the resolution loop should continue.
|
||||
clear_matches :: (board: *Board) -> s64 {
|
||||
m := find_matches(board);
|
||||
clear_cells(board, @m)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user