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>
61 lines
2.1 KiB
Dart
61 lines
2.1 KiB
Dart
import 'package:block_seasons/game/models/piece.dart';
|
|
import 'package:block_seasons/game/models/piece_library.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
group('PieceLibrary', () {
|
|
test('has a rich fixed-orientation shape set', () {
|
|
expect(PieceLibrary.all.length, greaterThanOrEqualTo(35));
|
|
});
|
|
|
|
test('ids are unique', () {
|
|
final ids = PieceLibrary.all.map((p) => p.id).toSet();
|
|
expect(ids.length, PieceLibrary.all.length);
|
|
});
|
|
|
|
test('every piece is normalized to its top-left bounding box', () {
|
|
for (final piece in PieceLibrary.all) {
|
|
final minDx =
|
|
piece.offsets.map((o) => o.$1).reduce((a, b) => a < b ? a : b);
|
|
final minDy =
|
|
piece.offsets.map((o) => o.$2).reduce((a, b) => a < b ? a : b);
|
|
expect(minDx, 0, reason: '${piece.id} not normalized in x');
|
|
expect(minDy, 0, reason: '${piece.id} not normalized in y');
|
|
}
|
|
});
|
|
|
|
test('offsets are unique and fit in a 5x5 bounding box', () {
|
|
for (final piece in PieceLibrary.all) {
|
|
expect(piece.offsets.toSet().length, piece.offsets.length,
|
|
reason: '${piece.id} has duplicate offsets');
|
|
for (final (dx, dy) in piece.offsets) {
|
|
expect(dx, inInclusiveRange(0, 4), reason: piece.id);
|
|
expect(dy, inInclusiveRange(0, 4), reason: piece.id);
|
|
}
|
|
}
|
|
});
|
|
|
|
test('weights are positive and tiers are 1..3', () {
|
|
for (final piece in PieceLibrary.all) {
|
|
expect(piece.weight, greaterThan(0), reason: piece.id);
|
|
expect(piece.tier, inInclusiveRange(1, 3), reason: piece.id);
|
|
}
|
|
});
|
|
|
|
test('contains the staple shapes', () {
|
|
for (final id in ['mono', 'square2', 'square3', 'line5_h', 'line5_v']) {
|
|
expect(PieceLibrary.byId(id), isA<Piece>());
|
|
}
|
|
});
|
|
|
|
test('byId throws on unknown id', () {
|
|
expect(() => PieceLibrary.byId('nope'), throwsStateError);
|
|
});
|
|
|
|
test('small pieces exist for tight late-game boards', () {
|
|
final smalls = PieceLibrary.all.where((p) => p.size <= 2);
|
|
expect(smalls.length, greaterThanOrEqualTo(3));
|
|
});
|
|
});
|
|
}
|