0210c14858
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>
64 lines
1.5 KiB
Dart
64 lines
1.5 KiB
Dart
import 'cell.dart';
|
|
|
|
/// Immutable 8x8 board state. Mutating operations return new instances.
|
|
///
|
|
/// Occupancy is mirrored in a 64-bit bitmask (bit y*8+x) so fullness checks
|
|
/// and placement scans are O(1) mask operations.
|
|
class GridState {
|
|
static const int size = 8;
|
|
static const int cellCount = size * size;
|
|
|
|
GridState.empty()
|
|
: _cells = List.filled(cellCount, Cell.empty),
|
|
_mask = 0;
|
|
|
|
const GridState._(this._cells, this._mask);
|
|
|
|
final List<Cell> _cells;
|
|
final int _mask;
|
|
|
|
static int _index(int x, int y) => y * size + x;
|
|
|
|
/// Raw occupancy bitmask; exposed for placement/clear mask math.
|
|
int get mask => _mask;
|
|
|
|
Cell cellAt(int x, int y) => _cells[_index(x, y)];
|
|
|
|
bool isOccupied(int x, int y) => (_mask >>> _index(x, y)) & 1 == 1;
|
|
|
|
int get occupiedCount {
|
|
var n = 0;
|
|
var m = _mask;
|
|
while (m != 0) {
|
|
m &= m - 1;
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
double get fillRatio => occupiedCount / cellCount;
|
|
|
|
GridState withCell(int x, int y, Cell cell) {
|
|
final cells = List.of(_cells);
|
|
final i = _index(x, y);
|
|
cells[i] = cell;
|
|
final mask =
|
|
cell.isOccupied ? (_mask | (1 << i)) : (_mask & ~(1 << i));
|
|
return GridState._(List.unmodifiable(cells), mask);
|
|
}
|
|
|
|
static int _rowMask(int y) => 0xFF << (y * size);
|
|
|
|
static int _colMask(int x) {
|
|
var m = 0;
|
|
for (var y = 0; y < size; y++) {
|
|
m |= 1 << _index(x, y);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
bool isRowFull(int y) => (_mask & _rowMask(y)) == _rowMask(y);
|
|
|
|
bool isColFull(int x) => (_mask & _colMask(x)) == _colMask(x);
|
|
}
|