Files
BlockSeasons/lib/game/engine/line_clear.dart
T
airkjw 0210c14858 Add pure-Dart engine core: RNG, grid, placement, line clear, scoring, piece generator
PCG32 seeded RNG; immutable 8x8 GridState with occupancy bitmask;
placement legality + anyPlacementExists; simultaneous row/col clears
with single-count gem credit; combo scoring with one-move grace;
weighted-bag generator with pity bias and depth-3 solvability nudge.
All TDD, 51 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:05:55 +09:00

57 lines
1.4 KiB
Dart

import '../models/cell.dart';
import '../models/grid.dart';
class ClearResult {
const ClearResult({
required this.grid,
required this.clearedRows,
required this.clearedCols,
required this.gemsCleared,
});
final GridState grid;
final List<int> clearedRows;
final List<int> clearedCols;
final int gemsCleared;
int get linesCleared => clearedRows.length + clearedCols.length;
}
/// Detects all simultaneously full rows/columns and clears them in one pass.
ClearResult detectAndClear(GridState grid) {
final rows = <int>[];
final cols = <int>[];
for (var y = 0; y < GridState.size; y++) {
if (grid.isRowFull(y)) rows.add(y);
}
for (var x = 0; x < GridState.size; x++) {
if (grid.isColFull(x)) cols.add(x);
}
if (rows.isEmpty && cols.isEmpty) {
return ClearResult(
grid: grid,
clearedRows: const [],
clearedCols: const [],
gemsCleared: 0,
);
}
final rowSet = rows.toSet();
final colSet = cols.toSet();
var gems = 0;
var next = grid;
for (var y = 0; y < GridState.size; y++) {
for (var x = 0; x < GridState.size; x++) {
if (!rowSet.contains(y) && !colSet.contains(x)) continue;
if (grid.cellAt(x, y).type == CellType.gem) gems++;
next = next.withCell(x, y, Cell.empty);
}
}
return ClearResult(
grid: next,
clearedRows: rows,
clearedCols: cols,
gemsCleared: gems,
);
}