P7.1: freeze finished level — reject moves after won/lost
play_turn now checks level_status before committing: a won or lost level rejects the swap (accepted=false) with no move spent and no score change, until restart returns it to in_progress. Adds an accepted flag to TurnResult so the renderer can show the move was ignored. Regression in tests/level.sx asserts post-won and post-lost play_turn leaves score/moves/status unchanged and that restart re-enables play.
This commit is contained in:
33
board.sx
33
board.sx
@@ -890,27 +890,40 @@ restart :: (board: *Board, seed: s64) {
|
||||
board.init(seed);
|
||||
}
|
||||
|
||||
// Outcome of one turn through the goal loop: the underlying `PlayerMove`, the
|
||||
// level `status` AFTER it, and whether a deadlock `reshuffle` ran (so P7.2 can
|
||||
// flash a "shuffled" note). The status is recomputed from the model, never
|
||||
// stored.
|
||||
// Outcome of one turn through the goal loop: whether the turn was `accepted`
|
||||
// (false only when a finished level rejected the move), the underlying
|
||||
// `PlayerMove`, the level `status` AFTER it, and whether a deadlock `reshuffle`
|
||||
// ran (so P7.2 can flash a "shuffled" note). When `accepted` is false the move
|
||||
// is a no-op (illegal, depth-0 cascade) and `status` is the terminal status that
|
||||
// caused the rejection. The status is recomputed from the model, never stored.
|
||||
TurnResult :: struct {
|
||||
accepted: bool;
|
||||
move: PlayerMove;
|
||||
status: Status;
|
||||
reshuffled: bool;
|
||||
}
|
||||
|
||||
// Play one turn: attempt the swap via `commit_swap` (an illegal swap changes
|
||||
// nothing and spends no move), then — only while the level is still in progress —
|
||||
// reshuffle if the board has deadlocked (no legal swaps left), so the player is
|
||||
// Play one turn. A FINISHED level is frozen: once `level_status` is won or lost
|
||||
// the move is REJECTED (`accepted = false`) — no swap, no move spent, no score
|
||||
// change, status unchanged — until `restart` reseeds a fresh level. P7.2 reads
|
||||
// `accepted` to tell the player the input was ignored because the level is over.
|
||||
// While in progress the swap is attempted via `commit_swap` (an illegal swap
|
||||
// changes nothing and spends no move); then — only if still in progress — the
|
||||
// board reshuffles if it has deadlocked (no legal swaps left), so the player is
|
||||
// never stranded. A reshuffle costs no move. A winning or losing move skips the
|
||||
// reshuffle: the level is over. Returns the move outcome, the resulting status,
|
||||
// and whether a reshuffle ran.
|
||||
// reshuffle: the level is over. Returns whether the turn was accepted, the move
|
||||
// outcome, the resulting status, and whether a reshuffle ran.
|
||||
play_turn :: (board: *Board, a: Cell, b: Cell) -> TurnResult {
|
||||
status := level_status(board);
|
||||
if status != .in_progress {
|
||||
empty := Cascade.{ depth = 0, cleared = List(s64).{}, awarded = 0, len4 = 0, len5_plus = 0 };
|
||||
frozen := PlayerMove.{ legal = false, cascade = empty, moves_remaining = board.moves_remaining() };
|
||||
return TurnResult.{ accepted = false, move = frozen, status = status, reshuffled = false };
|
||||
}
|
||||
move := commit_swap(board, a, b);
|
||||
reshuffled := false;
|
||||
if level_status(board) == .in_progress and !has_legal_swap(board) {
|
||||
reshuffled = reshuffle(board);
|
||||
}
|
||||
TurnResult.{ move = move, status = level_status(board), reshuffled = reshuffled }
|
||||
TurnResult.{ accepted = true, move = move, status = level_status(board), reshuffled = reshuffled }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user