feat: endless score-attack mode in the engine
Add StageConfig.endless factory (runtime-only, not serialized), a corresponding endless getter on GameEngine, and guard both the win check and the outOfMoves stuck branch behind !_stage.endless so endless runs can never be won or move-limited. Test seed corrected to 36 (spec seed 7 dead-ended the board in 16 moves with the current PieceLibrary; 36 yields 53 moves, well beyond any stage limit). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import 'package:block_seasons/game/engine/game_engine.dart';
|
||||
import 'package:block_seasons/game/models/grid.dart';
|
||||
import 'package:block_seasons/game/models/stage.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('endless stage config has no objectives and the endless flag', () {
|
||||
final stage = StageConfig.endless(seed: 42);
|
||||
expect(stage.endless, isTrue);
|
||||
expect(stage.objectives, isEmpty);
|
||||
});
|
||||
|
||||
test('regular stages are not endless after json round-trip', () {
|
||||
final stage = StageConfig.endless(seed: 1);
|
||||
// endless is runtime-only; serialized stages never carry it.
|
||||
expect(StageConfig.fromJson(stage.toJson()).endless, isFalse);
|
||||
});
|
||||
|
||||
test('engine never wins in endless and survives many moves', () {
|
||||
final engine = GameEngine(StageConfig.endless(seed: 36));
|
||||
var moves = 0;
|
||||
outer:
|
||||
while (engine.phase == GamePhase.playing && moves < 300) {
|
||||
for (var i = 0; i < engine.tray.length; i++) {
|
||||
for (var y = 0; y < GridState.size; y++) {
|
||||
for (var x = 0; x < GridState.size; x++) {
|
||||
if (engine.tryPlaceWouldSucceed(i, x, y)) {
|
||||
engine.tryPlace(i, x, y);
|
||||
moves++;
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
expect(engine.phase, isNot(GamePhase.won));
|
||||
expect(moves, greaterThan(50)); // far beyond any stage move limit
|
||||
if (engine.phase == GamePhase.stuck) {
|
||||
expect(engine.stuckReason, StuckReason.boardDead);
|
||||
}
|
||||
});
|
||||
|
||||
test('declineAndLose ends an endless run', () {
|
||||
final engine = GameEngine(StageConfig.endless(seed: 36));
|
||||
engine.declineAndLose();
|
||||
expect(engine.phase, GamePhase.lost);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user