P7.1: turn / goal state machine (pure sx)
Add a thin, deterministic level loop over the headless model in board.sx:
- target_score: per-level score goal (DEFAULT_TARGET_SCORE=1500), seeded by init.
- Status (in_progress/won/lost) derived purely from score/target/move budget via
level_status; won is checked before lost so meeting the goal on the final move
wins. status_name for the HUD/snapshots.
- has_legal_swap: allocation-free deadlock probe (first legal pair short-circuits).
- reshuffle: Fisher-Yates over existing gems via the board's seeded RNG until the
arrangement has no immediate match and at least one legal move; consumes no
move, terminates via MAX_RESHUFFLE_TRIES.
- restart: reseed a fresh, reproducible level (resets cells/score/moves/goal).
- play_turn / TurnResult: commit_swap then reshuffle on deadlock while in
progress, reporting the resulting status.
tests/level.sx (golden tests/expected/level.{stdout,exit}) asserts: start
in_progress; one legal swap crossing a low goal -> won transition; budget
exhausted below an unreachable goal -> lost transition; a provably deadlocked
diagonal Latin-square board ((col-row) mod 6) reshuffles to >=1 legal move with
no immediate match and no move spent; restart resets progress and a fixed seed
reproduces the same starting board.
Gate: sx build --target ios-sim main.sx (exit 0); bash tools/run_tests.sh
(17 passed, 0 failed).
This commit is contained in:
1
tests/expected/level.exit
Normal file
1
tests/expected/level.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
74
tests/expected/level.stdout
Normal file
74
tests/expected/level.stdout
Normal file
@@ -0,0 +1,74 @@
|
||||
== level (turn / goal state machine) ==
|
||||
== start-in-progress ==
|
||||
RRPPOGRG
|
||||
PGPOPRRO
|
||||
YYBBYRYB
|
||||
GBYYRGGP
|
||||
OGBRRORY
|
||||
BYRRPRBG
|
||||
YOYYROBB
|
||||
OROBPPRB
|
||||
score 0 target 1500 moves_remaining 30 status in_progress
|
||||
== win-transition ==
|
||||
RROGOGOG
|
||||
GGROGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
before: score 0 target 30 moves_remaining 5 status in_progress
|
||||
after: legal true awarded 30 reshuffled false
|
||||
after: score 30 moves_remaining 4 status won
|
||||
RBRGOGOG
|
||||
GGOOGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
== lose-transition ==
|
||||
RROGOGOG
|
||||
GGROGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
OGOGOGOG
|
||||
GOGOGOGO
|
||||
before: score 0 target 1000000 moves_remaining 1 status in_progress
|
||||
after: legal true score 30 moves_remaining 0 status lost
|
||||
== deadlock-reshuffle ==
|
||||
ROYGBPRO
|
||||
PROYGBPR
|
||||
BPROYGBP
|
||||
GBPROYGB
|
||||
YGBPROYG
|
||||
OYGBPROY
|
||||
ROYGBPRO
|
||||
PROYGBPR
|
||||
before: matches 0 legal_swaps 0 has_legal_swap false
|
||||
reshuffled true matches 0 legal_swaps 9
|
||||
after: score 0 moves_made 0
|
||||
BGGYORYR
|
||||
RRYGOPBY
|
||||
YRYBPRGB
|
||||
OOBGBPRG
|
||||
RPRPYRPO
|
||||
OBBPOOPG
|
||||
OBGGOPGY
|
||||
YPRYBORP
|
||||
== restart ==
|
||||
dirty: score 500 moves_made 7 status in_progress
|
||||
after restart: score 0 moves_made 0 moves_remaining 30 status in_progress
|
||||
RRPPOGRG
|
||||
PGPOPRRO
|
||||
YYBBYRYB
|
||||
GBYYRGGP
|
||||
OGBRRORY
|
||||
BYRRPRBG
|
||||
YOYYROBB
|
||||
OROBPPRB
|
||||
ok: level / turn-goal state machine
|
||||
Reference in New Issue
Block a user