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 _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); }