A few Boolean flags quickly become confusing if they independently mutate state. Replace scattered toggles with a transition function. Given a valid World and Controls, apply_commands returns the resulting World and does no movement.
Our modes are running, paused, over and stopped. Paused can resume. Over needs a fresh round. Stopped means the application has committed to shutting down, so it is terminal even if a restart appears in the same frame.
Write command priority as part of the contract. For a nonterminal world: quit wins, then restart, then pause. A simultaneous quit and restart must not reopen a closing window. A simultaneous restart and pause starts a new running round rather than immediately pausing it.
The order is independent of how the operating system delivered key messages. read_controls already coalesced event names into flags.
def command_choice(quit=False, restart=False, pause=False):
if quit: return "stopped"
if restart: return "new running round"
if pause: return "toggle active mode"
return "unchanged"
print(command_choice(quit=True, restart=True))
print(command_choice(restart=True, pause=True))Pause changes only mode; positions and counters remain equal. Restart calls new_game with the same Config, clearing counters and restoring the initial spawn. Pause in over mode does nothing because the round has no lives left. Moving left/right is not a command transition and must not move anything in this function.
Clean shutdown has two parts. The model transitions to stopped so the main loop can finish. The adapter owns the real display and fonts, so its setup and loop are wrapped in try/finally with pygame.quit in finally. Returning a stopped World cannot itself guarantee that an external library released resources.
Test the combination cases as well as each individual command. They provide more useful evidence than asserting a list of mode names exists.
resources = []
try:
resources.append("display opened")
print("loop exits")
finally:
resources.append("display released")
print(resources)Complete apply_commands and verify that quit beats restart, restart beats pause and stopped cannot resume. Check the custom-configuration restart too.
In the capstone, step will call this transition before motion and treat a command frame as a boundary with no displacement. The desktop renderer continues showing paused or game-over state until the next command.