CodeRigor

LESSON

Make pause, restart and quit explicit transitions

Define command priority, terminal shutdown and restart behavior using a small state machine.

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.

Four modes with different exits
start / 3
Pause toggles an active round, exhausting lives produces over, restart creates a new round, and quit enters terminal stopped.
Four modes with different exits
Pause toggles an active round, exhausting lives produces over, restart creates a new round, and quit enters terminal stopped.

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.

Python
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.

A command decision before movement
start / 3
The first applicable guard wins. A command frame returns its transition without moving the newly restarted or paused world.
A command decision before movement
The first applicable guard wins. A command frame returns its transition without moving the newly restarted or paused world.
Python
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.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Optional long-form companion. Our catch game and model exercises are original and self-contained.