Boulder Dash

Source: src/boulder_dash.c · 720 lines · 17 functions.

Screen captures

Views of this part running on the Mini Arcade.

Boulder Dash game screen on the Mini Arcade
Boulder Dash showing the cave, player, and movable objects.

Module entry points

These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.

How to read these diagrams

Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.

These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.

Functions in this file

boulderDashNextLevelRandom() · source line 155
static uint32_t boulderDashNextLevelRandom(void)
  1. Executeboulder_dash_level_random_state = boulder_dash_level_random_state * 1664525U + 1013904223U;
  2. Exit this functionreturn boulder_dash_level_random_state;
Read original function source
static uint32_t boulderDashNextLevelRandom(void)
{
    // Tiny deterministic PRNG: its state begins from the level's fixed seed,
    // so the generated layouts do not vary between separate plays.
    boulder_dash_level_random_state = boulder_dash_level_random_state * 1664525U + 1013904223U;
    return boulder_dash_level_random_state;
}
boulderDashIsReservedLevelCell() · source line 163
static bool boulderDashIsReservedLevelCell(int row, int column)
  1. Exit this functionreturn (row <= 2 && column <= 2) || (row >= BOULDER_DASH_CAVE_ROWS - 3 && column >= BOULDER_DASH_CAVE_COLUMNS - 3);
Read original function source
static bool boulderDashIsReservedLevelCell(int row, int column)
{
    // Preserve an open, safe two-by-two area around the upper-left spawn and
    // lower-right exit, independent of generated barrier/item placement.
    return (row <= 2 && column <= 2) ||
           (row >= BOULDER_DASH_CAVE_ROWS - 3 &&
            column >= BOULDER_DASH_CAVE_COLUMNS - 3);
}
boulderDashWalkableCaveIsConnected() · source line 172
static bool boulderDashWalkableCaveIsConnected(void)
  1. Executebool visited[BOULDER_DASH_CAVE_ROWS][BOULDER_DASH_CAVE_COLUMNS] = {{false}};
  2. Executeuint8_t pending_cells[BOULDER_DASH_CAVE_ROWS * BOULDER_DASH_CAVE_COLUMNS];
  3. Executeuint16_t read_index = 0U;
  4. Executeuint16_t write_index = 0U;
  5. Executepending_cells[write_index++] = BOULDER_DASH_CAVE_COLUMNS + 1U;
  6. Executevisited[1][1] = true;
  7. WHILE loopread_index < write_index

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst uint8_t cell = pending_cells[read_index++];
      2. Executeconst int row = cell / BOULDER_DASH_CAVE_COLUMNS;
      3. Executeconst int column = cell % BOULDER_DASH_CAVE_COLUMNS;
      4. Executestatic const int row_offsets[4] = {-1, 1, 0, 0};
      5. Executestatic const int column_offsets[4] = {0, 0, -1, 1};
      6. FOR loopint direction = 0; direction < 4; ++direction

        Repeat body while the loop condition permits; then continue below.

          1. Executeconst int next_row = row + row_offsets[direction];
          2. Executeconst int next_column = column + column_offsets[direction];
          3. Decisionnext_row < 0 || next_row >= BOULDER_DASH_CAVE_ROWS || next_column < 0 || next_column >= BOULDER_DASH_CAVE_COLUMNS || visited[next_row][next_column] || boulder_dash_cave[next_row][next_column] == BOULDER_DASH_STEEL
            True
              1. Next loop iterationcontinue;
            False

            Continue after this decision.

          4. Executevisited[next_row][next_column] = true;
          5. Executepending_cells[write_index++] = (uint8_t)(next_row * BOULDER_DASH_CAVE_COLUMNS + next_column);
  8. FOR loopint row = 1; row < BOULDER_DASH_CAVE_ROWS - 1; ++row

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint column = 1; column < BOULDER_DASH_CAVE_COLUMNS - 1; ++column

        Repeat body while the loop condition permits; then continue below.

          1. Decisionboulder_dash_cave[row][column] != BOULDER_DASH_STEEL && !visited[row][column]
            True
              1. Exit this functionreturn false;
            False

            Continue after this decision.

  9. Exit this functionreturn true;
Read original function source
static bool boulderDashWalkableCaveIsConnected(void)
{
    // Each proposed steel block is accepted only if every remaining non-steel
    // tile can still be reached from the spawn. This prevents a generated wall
    // pattern from sealing off part of the cave before gems are added.
    bool visited[BOULDER_DASH_CAVE_ROWS][BOULDER_DASH_CAVE_COLUMNS] = {{false}};
    uint8_t pending_cells[BOULDER_DASH_CAVE_ROWS * BOULDER_DASH_CAVE_COLUMNS];
    uint16_t read_index = 0U;
    uint16_t write_index = 0U;

    pending_cells[write_index++] = BOULDER_DASH_CAVE_COLUMNS + 1U;
    visited[1][1] = true;
    while (read_index < write_index) {
        const uint8_t cell = pending_cells[read_index++];
        const int row = cell / BOULDER_DASH_CAVE_COLUMNS;
        const int column = cell % BOULDER_DASH_CAVE_COLUMNS;
        static const int row_offsets[4] = {-1, 1, 0, 0};
        static const int column_offsets[4] = {0, 0, -1, 1};

        for (int direction = 0; direction < 4; ++direction) {
            const int next_row = row + row_offsets[direction];
            const int next_column = column + column_offsets[direction];
            if (next_row < 0 || next_row >= BOULDER_DASH_CAVE_ROWS ||
                next_column < 0 || next_column >= BOULDER_DASH_CAVE_COLUMNS ||
                visited[next_row][next_column] ||
                boulder_dash_cave[next_row][next_column] == BOULDER_DASH_STEEL) {
                continue;
            }
            visited[next_row][next_column] = true;
            pending_cells[write_index++] =
                (uint8_t)(next_row * BOULDER_DASH_CAVE_COLUMNS + next_column);
        }
    }

    for (int row = 1; row < BOULDER_DASH_CAVE_ROWS - 1; ++row) {
        for (int column = 1; column < BOULDER_DASH_CAVE_COLUMNS - 1; ++column) {
            if (boulder_dash_cave[row][column] != BOULDER_DASH_STEEL &&
                !visited[row][column]) {
                return false;
            }
        }
    }
    return true;
}
placeProceduralLevelTiles() · source line 217
static void placeProceduralLevelTiles(boulder_dash_tile_t tile, uint8_t count)

Calls into this documentation:

  1. Executeuint8_t placed = 0U;
  2. Executeuint16_t attempts = 0U;
  3. WHILE loopplaced < count && attempts++ < BOULDER_DASH_LEVEL_PLACEMENT_ATTEMPTS

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst int row = 1 + (int)(boulderDashNextLevelRandom() % (BOULDER_DASH_CAVE_ROWS - 2));
      2. Executeconst int column = 1 + (int)(boulderDashNextLevelRandom() % (BOULDER_DASH_CAVE_COLUMNS - 2));
      3. DecisionboulderDashIsReservedLevelCell(row, column) || boulder_dash_cave[row][column] != BOULDER_DASH_DIRT
        True
          1. Next loop iterationcontinue;
        False

        Continue after this decision.

      4. Decisiontile == BOULDER_DASH_BOULDER && boulder_dash_cave[row + 1][column] != BOULDER_DASH_DIRT
        True
          1. Next loop iterationcontinue;
        False

        Continue after this decision.

      5. Executeboulder_dash_cave[row][column] = tile;
      6. Execute++placed;
Read original function source
static void placeProceduralLevelTiles(boulder_dash_tile_t tile, uint8_t count)
{
    uint8_t placed = 0U;
    uint16_t attempts = 0U;
    while (placed < count && attempts++ < BOULDER_DASH_LEVEL_PLACEMENT_ATTEMPTS) {
        const int row = 1 + (int)(boulderDashNextLevelRandom() %
                                  (BOULDER_DASH_CAVE_ROWS - 2));
        const int column = 1 + (int)(boulderDashNextLevelRandom() %
                                     (BOULDER_DASH_CAVE_COLUMNS - 2));
        if (boulderDashIsReservedLevelCell(row, column) ||
            boulder_dash_cave[row][column] != BOULDER_DASH_DIRT) {
            continue;
        }
        // New boulders begin on dirt rather than open space, so they do not
        // drop the instant the level begins.
        if (tile == BOULDER_DASH_BOULDER &&
            boulder_dash_cave[row + 1][column] != BOULDER_DASH_DIRT) {
            continue;
        }
        boulder_dash_cave[row][column] = tile;
        ++placed;
    }
}
buildProceduralBoulderDashLevel() · source line 241
static void buildProceduralBoulderDashLevel(const boulder_dash_level_definition_t *level)

Calls into this documentation:

  1. Executeboulder_dash_level_random_state = level->seed;
  2. FOR loopint row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column

        Repeat body while the loop condition permits; then continue below.

          1. Executeboulder_dash_cave[row][column] = row == 0 || row == BOULDER_DASH_CAVE_ROWS - 1 || column == 0 || column == BOULDER_DASH_CAVE_COLUMNS - 1 ? BOULDER_DASH_STEEL : BOULDER_DASH_DIRT;
  3. Executeboulder_dash_cave[1][1] = BOULDER_DASH_PLAYER;
  4. Executeboulder_dash_cave[1][2] = BOULDER_DASH_EMPTY;
  5. Executeboulder_dash_cave[2][1] = BOULDER_DASH_EMPTY;
  6. Executeboulder_dash_cave[2][2] = BOULDER_DASH_EMPTY;
  7. Executeboulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 2][BOULDER_DASH_CAVE_COLUMNS - 2] = BOULDER_DASH_EXIT;
  8. Executeboulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 2][BOULDER_DASH_CAVE_COLUMNS - 3] = BOULDER_DASH_EMPTY;
  9. Executeboulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 3][BOULDER_DASH_CAVE_COLUMNS - 2] = BOULDER_DASH_EMPTY;
  10. Executeboulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 3][BOULDER_DASH_CAVE_COLUMNS - 3] = BOULDER_DASH_EMPTY;
  11. Executeuint8_t steel_placed = 0U;
  12. Executeuint16_t attempts = 0U;
  13. WHILE loopsteel_placed < level->steel_blocks && attempts++ < BOULDER_DASH_LEVEL_PLACEMENT_ATTEMPTS

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst int row = 1 + (int)(boulderDashNextLevelRandom() % (BOULDER_DASH_CAVE_ROWS - 2));
      2. Executeconst int column = 1 + (int)(boulderDashNextLevelRandom() % (BOULDER_DASH_CAVE_COLUMNS - 2));
      3. DecisionboulderDashIsReservedLevelCell(row, column) || boulder_dash_cave[row][column] != BOULDER_DASH_DIRT
        True
          1. Next loop iterationcontinue;
        False

        Continue after this decision.

      4. Executeboulder_dash_cave[row][column] = BOULDER_DASH_STEEL;
      5. DecisionboulderDashWalkableCaveIsConnected()
        True
          1. Execute++steel_placed;
        False
          1. Executeboulder_dash_cave[row][column] = BOULDER_DASH_DIRT;
  14. ExecuteplaceProceduralLevelTiles(BOULDER_DASH_DIAMOND, level->diamonds);
  15. ExecuteplaceProceduralLevelTiles(BOULDER_DASH_BOULDER, level->boulders);
Read original function source
static void buildProceduralBoulderDashLevel(const boulder_dash_level_definition_t *level)
{
    boulder_dash_level_random_state = level->seed;
    for (int row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            boulder_dash_cave[row][column] =
                row == 0 || row == BOULDER_DASH_CAVE_ROWS - 1 ||
                column == 0 || column == BOULDER_DASH_CAVE_COLUMNS - 1
                    ? BOULDER_DASH_STEEL
                    : BOULDER_DASH_DIRT;
        }
    }

    boulder_dash_cave[1][1] = BOULDER_DASH_PLAYER;
    boulder_dash_cave[1][2] = BOULDER_DASH_EMPTY;
    boulder_dash_cave[2][1] = BOULDER_DASH_EMPTY;
    boulder_dash_cave[2][2] = BOULDER_DASH_EMPTY;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 2][BOULDER_DASH_CAVE_COLUMNS - 2] =
        BOULDER_DASH_EXIT;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 2][BOULDER_DASH_CAVE_COLUMNS - 3] =
        BOULDER_DASH_EMPTY;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 3][BOULDER_DASH_CAVE_COLUMNS - 2] =
        BOULDER_DASH_EMPTY;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 3][BOULDER_DASH_CAVE_COLUMNS - 3] =
        BOULDER_DASH_EMPTY;

    uint8_t steel_placed = 0U;
    uint16_t attempts = 0U;
    while (steel_placed < level->steel_blocks &&
           attempts++ < BOULDER_DASH_LEVEL_PLACEMENT_ATTEMPTS) {
        const int row = 1 + (int)(boulderDashNextLevelRandom() %
                                  (BOULDER_DASH_CAVE_ROWS - 2));
        const int column = 1 + (int)(boulderDashNextLevelRandom() %
                                     (BOULDER_DASH_CAVE_COLUMNS - 2));
        if (boulderDashIsReservedLevelCell(row, column) ||
            boulder_dash_cave[row][column] != BOULDER_DASH_DIRT) {
            continue;
        }
        boulder_dash_cave[row][column] = BOULDER_DASH_STEEL;
        if (boulderDashWalkableCaveIsConnected()) {
            ++steel_placed;
        } else {
            boulder_dash_cave[row][column] = BOULDER_DASH_DIRT;
        }
    }

    placeProceduralLevelTiles(BOULDER_DASH_DIAMOND, level->diamonds);
    placeProceduralLevelTiles(BOULDER_DASH_BOULDER, level->boulders);
}
resetBoulderDashCave() · source line 291
static void resetBoulderDashCave(uint32_t now_ms, bool reset_run_score)

Calls into this documentation:

  1. Executeconst boulder_dash_level_definition_t *const level = &boulder_dash_levels[boulder_dash_level_index];
  2. Decisionboulder_dash_level_index == 0U
    True
      1. Executememcpy(boulder_dash_cave, boulder_dash_level_one_cave, sizeof(boulder_dash_cave));
    False
      1. ExecutebuildProceduralBoulderDashLevel(level);
  3. Executeboulder_dash_diamonds_collected = 0U;
  4. Executeboulder_dash_diamonds_required = 0U;
  5. Decisionreset_run_score
    True
    1. Executeboulder_dash_score = 0;
    False

    Continue after this decision.

  6. Executeboulder_dash_roll_left_first = true;
  7. FOR loopint row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column

        Repeat body while the loop condition permits; then continue below.

          1. Decisionboulder_dash_cave[row][column] == BOULDER_DASH_PLAYER
            True
              1. Executeboulder_dash_player_column = column;
              2. Executeboulder_dash_player_row = row;
              3. Executeboulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
            False
            1. Decisionboulder_dash_cave[row][column] == BOULDER_DASH_DIAMOND
              True
                1. Execute++boulder_dash_diamonds_required;
              False

              Continue after this decision.

  8. Executeboulder_dash_state = BOULDER_DASH_PLAYING;
  9. Executeboulder_dash_last_move_at = now_ms;
  10. Executeboulder_dash_last_gravity_at = now_ms;
Read original function source
static void resetBoulderDashCave(uint32_t now_ms, bool reset_run_score)
{
    const boulder_dash_level_definition_t *const level =
        &boulder_dash_levels[boulder_dash_level_index];
    if (boulder_dash_level_index == 0U) {
        memcpy(boulder_dash_cave, boulder_dash_level_one_cave, sizeof(boulder_dash_cave));
    } else {
        buildProceduralBoulderDashLevel(level);
    }
    boulder_dash_diamonds_collected = 0U;
    boulder_dash_diamonds_required = 0U;
    if (reset_run_score) boulder_dash_score = 0;
    boulder_dash_roll_left_first = true;

    // The player is stored as coordinates rather than a map tile so the tile
    // beneath them remains available for boulders and other future interactions.
    for (int row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            if (boulder_dash_cave[row][column] == BOULDER_DASH_PLAYER) {
                boulder_dash_player_column = column;
                boulder_dash_player_row = row;
                boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
            } else if (boulder_dash_cave[row][column] == BOULDER_DASH_DIAMOND) {
                ++boulder_dash_diamonds_required;
            }
        }
    }

    boulder_dash_state = BOULDER_DASH_PLAYING;
    boulder_dash_last_move_at = now_ms;
    boulder_dash_last_gravity_at = now_ms;
}
boulderDashCrushPlayer() · source line 324
static void boulderDashCrushPlayer(void)
  1. Decisionboulder_dash_lives > 0U
    True
    1. Execute--boulder_dash_lives;
    False

    Continue after this decision.

  2. Executeboulder_dash_state = boulder_dash_lives == 0U ? BOULDER_DASH_GAME_OVER : BOULDER_DASH_CRUSHED;
Read original function source
static void boulderDashCrushPlayer(void)
{
    // A loss always consumes one of the run's lives. The level remains ready
    // for an A/K restart while a life remains; the third loss ends the run.
    if (boulder_dash_lives > 0U) --boulder_dash_lives;
    boulder_dash_state = boulder_dash_lives == 0U
                             ? BOULDER_DASH_GAME_OVER
                             : BOULDER_DASH_CRUSHED;
}
drawBoulderDashTile() · source line 334
static void drawBoulderDashTile(uint16_t *frame, int x, int y, boulder_dash_tile_t tile,
                                bool exit_open)

Calls into this documentation:

  1. Select a casetile

    Enter matching case; follow source fall-through until a break, return or end.

      1. Case / labelcase BOULDER_DASH_EMPTY:
      2. Executefill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
      3. Exit enclosing loop or switchbreak;
      4. Case / labelcase BOULDER_DASH_DIRT:
      5. Executefill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_SADDLEBROWN);
      6. Executedraw_bitmap_scaled(frame, x, y, boulder_dash_dirt_mask, 16, 16, 16, 16, COLOR_PERU);
      7. Exit enclosing loop or switchbreak;
      8. Case / labelcase BOULDER_DASH_STEEL:
      9. Executefill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_DARKSLATEGRAY);
      10. Executedraw_bitmap_scaled(frame, x, y, boulder_dash_steel_mask, 16, 16, 16, 16, COLOR_LIGHTGREY);
      11. Exit enclosing loop or switchbreak;
      12. Case / labelcase BOULDER_DASH_BOULDER:
      13. Executefill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
      14. Executedraw_bitmap_scaled(frame, x, y, boulder_dash_boulder_mask, 16, 16, 16, 16, COLOR_SLATEGRAY);
      15. Exit enclosing loop or switchbreak;
      16. Case / labelcase BOULDER_DASH_DIAMOND:
      17. Executefill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_DARKBLUE);
      18. Executedraw_bitmap_scaled(frame, x, y, boulder_dash_diamond_mask, 16, 16, 16, 16, COLOR_CYAN);
      19. Exit enclosing loop or switchbreak;
      20. Case / labelcase BOULDER_DASH_PLAYER:
      21. Executefill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
      22. Executedraw_bitmap_scaled(frame, x, y, boulder_dash_player_mask, 16, 16, 16, 16, COLOR_ORANGE);
      23. Exit enclosing loop or switchbreak;
      24. Case / labelcase BOULDER_DASH_EXIT:
      25. Executefill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, exit_open ? COLOR_DARKGREEN : COLOR_DARKRED);
      26. Executedraw_bitmap_scaled(frame, x, y, boulder_dash_exit_mask, 16, 16, 16, 16, exit_open ? COLOR_YELLOW : COLOR_LIGHTGREY);
      27. Exit enclosing loop or switchbreak;
Read original function source
static void drawBoulderDashTile(uint16_t *frame, int x, int y, boulder_dash_tile_t tile,
                                bool exit_open)
{
    switch (tile) {
        case BOULDER_DASH_EMPTY:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
            break;
        case BOULDER_DASH_DIRT:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_SADDLEBROWN);
            draw_bitmap_scaled(frame, x, y, boulder_dash_dirt_mask, 16, 16, 16, 16, COLOR_PERU);
            break;
        case BOULDER_DASH_STEEL:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_DARKSLATEGRAY);
            draw_bitmap_scaled(frame, x, y, boulder_dash_steel_mask, 16, 16, 16, 16, COLOR_LIGHTGREY);
            break;
        case BOULDER_DASH_BOULDER:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
            draw_bitmap_scaled(frame, x, y, boulder_dash_boulder_mask, 16, 16, 16, 16, COLOR_SLATEGRAY);
            break;
        case BOULDER_DASH_DIAMOND:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_DARKBLUE);
            draw_bitmap_scaled(frame, x, y, boulder_dash_diamond_mask, 16, 16, 16, 16, COLOR_CYAN);
            break;
        case BOULDER_DASH_PLAYER:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
            draw_bitmap_scaled(frame, x, y, boulder_dash_player_mask, 16, 16, 16, 16, COLOR_ORANGE);
            break;
        case BOULDER_DASH_EXIT:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE,
                      exit_open ? COLOR_DARKGREEN : COLOR_DARKRED);
            draw_bitmap_scaled(frame, x, y, boulder_dash_exit_mask, 16, 16, 16, 16,
                               exit_open ? COLOR_YELLOW : COLOR_LIGHTGREY);
            break;
    }
}
boulderDashExitOpen() · source line 370
static bool boulderDashExitOpen(void)
  1. Exit this functionreturn boulder_dash_diamonds_collected >= boulder_dash_diamonds_required;
Read original function source
static bool boulderDashExitOpen(void)
{
    return boulder_dash_diamonds_collected >= boulder_dash_diamonds_required;
}
tryMoveBoulderDashPlayer() · source line 375
static void tryMoveBoulderDashPlayer(int column_delta, int row_delta, bool hold_a_to_stay,
                                     uint32_t now_ms)

Calls into this documentation:

  1. Decisionboulder_dash_state != BOULDER_DASH_PLAYING
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Executeconst int next_column = boulder_dash_player_column + column_delta;
  3. Executeconst int next_row = boulder_dash_player_row + row_delta;
  4. Decisionnext_column < 0 || next_column >= BOULDER_DASH_CAVE_COLUMNS || next_row < 0 || next_row >= BOULDER_DASH_CAVE_ROWS
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  5. Executeboulder_dash_tile_t *const destination = &boulder_dash_cave[next_row][next_column];
  6. Decision*destination == BOULDER_DASH_STEEL
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  7. Decision*destination == BOULDER_DASH_BOULDER
    True
      1. Executeconst int push_column = next_column + column_delta;
      2. Decisionrow_delta != 0 || push_column < 0 || push_column >= BOULDER_DASH_CAVE_COLUMNS || boulder_dash_cave[next_row][push_column] != BOULDER_DASH_EMPTY
        True
        1. Exit this functionreturn;
        False

        Continue after this decision.

      3. Executeboulder_dash_cave[next_row][push_column] = BOULDER_DASH_BOULDER;
      4. Execute*destination = BOULDER_DASH_EMPTY;
      5. Decision!hold_a_to_stay
        True
          1. Executeboulder_dash_player_column = next_column;
          2. Executeboulder_dash_player_row = next_row;
        False

        Continue after this decision.

      6. Exit this functionreturn;
    False

    Continue after this decision.

  8. Decision*destination == BOULDER_DASH_EXIT
    True
      1. DecisionboulderDashExitOpen()
        True
          1. Executeboulder_dash_state = BOULDER_DASH_LEVEL_FLASH;
          2. Executeboulder_dash_level_flash_started_at = now_ms;
          3. Executeboulder_dash_level_flash_light = true;
        False

        Continue after this decision.

      2. Exit this functionreturn;
    False

    Continue after this decision.

  9. Decision*destination == BOULDER_DASH_DIRT
    True
      1. Executeboulder_dash_score -= BOULDER_DASH_NEW_DIRT_PENALTY;
    False
    1. Decision*destination == BOULDER_DASH_DIAMOND
      True
        1. Execute++boulder_dash_diamonds_collected;
        2. Executeboulder_dash_score += BOULDER_DASH_DIAMOND_POINTS;
      False

      Continue after this decision.

  10. Execute*destination = BOULDER_DASH_EMPTY;
  11. Executeboulder_dash_player_column = next_column;
  12. Executeboulder_dash_player_row = next_row;
Read original function source
static void tryMoveBoulderDashPlayer(int column_delta, int row_delta, bool hold_a_to_stay,
                                     uint32_t now_ms)
{
    if (boulder_dash_state != BOULDER_DASH_PLAYING) return;

    const int next_column = boulder_dash_player_column + column_delta;
    const int next_row = boulder_dash_player_row + row_delta;
    if (next_column < 0 || next_column >= BOULDER_DASH_CAVE_COLUMNS ||
        next_row < 0 || next_row >= BOULDER_DASH_CAVE_ROWS) return;

    boulder_dash_tile_t *const destination = &boulder_dash_cave[next_row][next_column];
    if (*destination == BOULDER_DASH_STEEL) return;
    if (*destination == BOULDER_DASH_BOULDER) {
        // Rocks can only be pushed sideways, and only into an already empty
        // cell. Dirt, diamonds, exits, and vertical pushes remain blocked.
        // Holding A makes this a careful push: the rock moves, but the player
        // remains in place. Without A, the player follows into the old rock tile.
        const int push_column = next_column + column_delta;
        if (row_delta != 0 || push_column < 0 || push_column >= BOULDER_DASH_CAVE_COLUMNS ||
            boulder_dash_cave[next_row][push_column] != BOULDER_DASH_EMPTY) return;
        boulder_dash_cave[next_row][push_column] = BOULDER_DASH_BOULDER;
        *destination = BOULDER_DASH_EMPTY;
        if (!hold_a_to_stay) {
            boulder_dash_player_column = next_column;
            boulder_dash_player_row = next_row;
        }
        return;
    }
    if (*destination == BOULDER_DASH_EXIT) {
        if (boulderDashExitOpen()) {
            boulder_dash_state = BOULDER_DASH_LEVEL_FLASH;
            boulder_dash_level_flash_started_at = now_ms;
            boulder_dash_level_flash_light = true;
        }
        return;
    }

    // Dirt disappears as it is crossed; diamonds do too, while adding to the
    // count needed to unlock the exit. Empty tiles cost nothing after their
    // first digging pass.
    if (*destination == BOULDER_DASH_DIRT) {
        boulder_dash_score -= BOULDER_DASH_NEW_DIRT_PENALTY;
    } else if (*destination == BOULDER_DASH_DIAMOND) {
        ++boulder_dash_diamonds_collected;
        boulder_dash_score += BOULDER_DASH_DIAMOND_POINTS;
    }
    *destination = BOULDER_DASH_EMPTY;
    boulder_dash_player_column = next_column;
    boulder_dash_player_row = next_row;
}
tryRollBoulder() · source line 426
static bool tryRollBoulder(int row, int column, int direction)

Calls into this documentation:

  1. Executeconst int side_column = column + direction;
  2. Executeconst int diagonal_row = row + 1;
  3. Decisionside_column < 0 || side_column >= BOULDER_DASH_CAVE_COLUMNS
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  4. Decisionboulder_dash_player_row == row && boulder_dash_player_column == side_column
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  5. Decisionboulder_dash_cave[row][side_column] != BOULDER_DASH_EMPTY
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  6. Decisionboulder_dash_player_row == diagonal_row && boulder_dash_player_column == side_column
    True
      1. Executeboulder_dash_cave[diagonal_row][side_column] = BOULDER_DASH_BOULDER;
      2. Executeboulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
      3. ExecuteboulderDashCrushPlayer();
      4. Exit this functionreturn true;
    False

    Continue after this decision.

  7. Decisionboulder_dash_cave[diagonal_row][side_column] != BOULDER_DASH_EMPTY
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  8. Executeboulder_dash_cave[diagonal_row][side_column] = BOULDER_DASH_BOULDER;
  9. Executeboulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
  10. Executeboulder_dash_roll_left_first = !boulder_dash_roll_left_first;
  11. Exit this functionreturn true;
Read original function source
static bool tryRollBoulder(int row, int column, int direction)
{
    const int side_column = column + direction;
    const int diagonal_row = row + 1;
    if (side_column < 0 || side_column >= BOULDER_DASH_CAVE_COLUMNS) return false;

    // A player beside the boulder blocks its path. A player in the diagonal
    // destination is struck by the rolling boulder just like a falling one.
    if (boulder_dash_player_row == row && boulder_dash_player_column == side_column) return false;
    if (boulder_dash_cave[row][side_column] != BOULDER_DASH_EMPTY) return false;
    if (boulder_dash_player_row == diagonal_row &&
        boulder_dash_player_column == side_column) {
        boulder_dash_cave[diagonal_row][side_column] = BOULDER_DASH_BOULDER;
        boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
        boulderDashCrushPlayer();
        return true;
    }
    if (boulder_dash_cave[diagonal_row][side_column] != BOULDER_DASH_EMPTY) return false;

    boulder_dash_cave[diagonal_row][side_column] = BOULDER_DASH_BOULDER;
    boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
    boulder_dash_roll_left_first = !boulder_dash_roll_left_first;
    return true;
}
updateBoulderDashGravity() · source line 451
static void updateBoulderDashGravity(void)

Calls into this documentation:

  1. FOR loopint row = BOULDER_DASH_CAVE_ROWS - 2; row >= 0; --row

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column

        Repeat body while the loop condition permits; then continue below.

          1. Decisionboulder_dash_cave[row][column] != BOULDER_DASH_BOULDER
            True
            1. Next loop iterationcontinue;
            False

            Continue after this decision.

          2. Executeconst int below_row = row + 1;
          3. Decisionboulder_dash_player_row == below_row && boulder_dash_player_column == column
            True
            1. Next loop iterationcontinue;
            False

            Continue after this decision.

          4. Executeconst boulder_dash_tile_t below_tile = boulder_dash_cave[below_row][column];
          5. Decisionbelow_tile == BOULDER_DASH_EMPTY
            True
              1. Executeboulder_dash_cave[below_row][column] = BOULDER_DASH_BOULDER;
              2. Executeboulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
              3. Next loop iterationcontinue;
            False

            Continue after this decision.

          6. Decisionbelow_tile != BOULDER_DASH_BOULDER && below_tile != BOULDER_DASH_DIAMOND
            True
              1. Next loop iterationcontinue;
            False

            Continue after this decision.

          7. Executeconst int first_direction = boulder_dash_roll_left_first ? -1 : 1;
          8. DecisiontryRollBoulder(row, column, first_direction) || tryRollBoulder(row, column, -first_direction)
            True
              1. Decisionboulder_dash_state != BOULDER_DASH_PLAYING
                True
                1. Exit this functionreturn;
                False

                Continue after this decision.

            False

            Continue after this decision.

Read original function source
static void updateBoulderDashGravity(void)
{
    // Bottom-up processing prevents a boulder from falling multiple cells in a
    // single gravity tick after it enters a new empty cell.
    for (int row = BOULDER_DASH_CAVE_ROWS - 2; row >= 0; --row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            if (boulder_dash_cave[row][column] != BOULDER_DASH_BOULDER) continue;

            const int below_row = row + 1;
            // A player directly underneath temporarily supports the boulder.
            // This permits digging sideways beneath it; once the player moves
            // clear, the empty cell below makes the boulder fall next tick.
            // Diagonal rolling remains dangerous and is handled in tryRollBoulder.
            if (boulder_dash_player_row == below_row &&
                boulder_dash_player_column == column) continue;
            const boulder_dash_tile_t below_tile = boulder_dash_cave[below_row][column];
            if (below_tile == BOULDER_DASH_EMPTY) {
                boulder_dash_cave[below_row][column] = BOULDER_DASH_BOULDER;
                boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
                continue;
            }

            // Only round boulders and diamonds provide a surface a boulder can
            // roll from. Dirt and steel deliberately hold it still.
            if (below_tile != BOULDER_DASH_BOULDER && below_tile != BOULDER_DASH_DIAMOND) {
                continue;
            }
            const int first_direction = boulder_dash_roll_left_first ? -1 : 1;
            if (tryRollBoulder(row, column, first_direction) ||
                tryRollBoulder(row, column, -first_direction)) {
                if (boulder_dash_state != BOULDER_DASH_PLAYING) return;
            }
        }
    }
}
startBoulderDash() · source line 487
void startBoulderDash(uint32_t now_ms)

Calls into this documentation:

  1. Executeboulder_dash_running = true;
  2. Executeboulder_dash_level_index = 0U;
  3. Executeboulder_dash_lives = BOULDER_DASH_STARTING_LIVES;
  4. ExecuteresetBoulderDashCave(now_ms, true);
Read original function source
void startBoulderDash(uint32_t now_ms)
{
    boulder_dash_running = true;
    boulder_dash_level_index = 0U;
    boulder_dash_lives = BOULDER_DASH_STARTING_LIVES;
    resetBoulderDashCave(now_ms, true);
}
stopBoulderDash() · source line 495
void stopBoulderDash(void)
  1. Executeboulder_dash_running = false;
Read original function source
void stopBoulderDash(void)
{
    boulder_dash_running = false;
}
boulderDashAction() · source line 500
void boulderDashAction(bool reset_cave, uint32_t now_ms)

Calls into this documentation:

  1. Decisionboulder_dash_running && reset_cave && boulder_dash_state == BOULDER_DASH_CRUSHED
    True
      1. ExecuteresetBoulderDashCave(now_ms, false);
    False
    1. Decisionboulder_dash_running && reset_cave && boulder_dash_state == BOULDER_DASH_COMPLETE
      True
        1. Executeboulder_dash_level_index = (uint8_t)((boulder_dash_level_index + 1U) % BOULDER_DASH_LEVEL_COUNT);
        2. ExecuteresetBoulderDashCave(now_ms, false);
      False
      1. Decisionboulder_dash_running && reset_cave && boulder_dash_state == BOULDER_DASH_GAME_OVER
        True
          1. Executeboulder_dash_level_index = 0U;
          2. Executeboulder_dash_lives = BOULDER_DASH_STARTING_LIVES;
          3. ExecuteresetBoulderDashCave(now_ms, true);
        False

        Continue after this decision.

Read original function source
void boulderDashAction(bool reset_cave, uint32_t now_ms)
{
    // During normal play A is held as the careful-push modifier. A/K resets
    // after death; after completion it advances through all ten levels. The
    // success flash is always allowed to finish before either action occurs.
    if (boulder_dash_running && reset_cave &&
        boulder_dash_state == BOULDER_DASH_CRUSHED) {
        resetBoulderDashCave(now_ms, false);
    } else if (boulder_dash_running && reset_cave &&
               boulder_dash_state == BOULDER_DASH_COMPLETE) {
        boulder_dash_level_index =
            (uint8_t)((boulder_dash_level_index + 1U) % BOULDER_DASH_LEVEL_COUNT);
        resetBoulderDashCave(now_ms, false);
    } else if (boulder_dash_running && reset_cave &&
               boulder_dash_state == BOULDER_DASH_GAME_OVER) {
        boulder_dash_level_index = 0U;
        boulder_dash_lives = BOULDER_DASH_STARTING_LIVES;
        resetBoulderDashCave(now_ms, true);
    }
}
updateBoulderDash() · source line 521
void updateBoulderDash(int x_offset, int y_offset, bool valid, bool left, bool right,
                       bool hold_a_to_stay, uint32_t now_ms)

Calls into this documentation:

  1. Decision!boulder_dash_running
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Decisionboulder_dash_state == BOULDER_DASH_LEVEL_FLASH
    True
      1. Executeconst uint32_t flash_elapsed_ms = now_ms - boulder_dash_level_flash_started_at;
      2. Executeboulder_dash_level_flash_light = (flash_elapsed_ms / BOULDER_DASH_LEVEL_FLASH_INTERVAL_MS) % 2U == 0U;
      3. Decisionflash_elapsed_ms >= BOULDER_DASH_LEVEL_FLASH_DURATION_MS
        True
          1. Executeboulder_dash_state = BOULDER_DASH_COMPLETE;
        False

        Continue after this decision.

      4. Exit this functionreturn;
    False

    Continue after this decision.

  3. Decisionboulder_dash_state != BOULDER_DASH_PLAYING
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  4. Executeint column_delta = 0;
  5. Executeint row_delta = 0;
  6. Decisionleft != right
    True
      1. Executecolumn_delta = left ? -1 : 1;
    False
    1. Decisionvalid && (x_offset >= BOULDER_DASH_JOYSTICK_THRESHOLD || x_offset <= -BOULDER_DASH_JOYSTICK_THRESHOLD || y_offset >= BOULDER_DASH_JOYSTICK_THRESHOLD || y_offset <= -BOULDER_DASH_JOYSTICK_THRESHOLD)
      True
        1. Executeconst int horizontal_strength = x_offset < 0 ? -x_offset : x_offset;
        2. Executeconst int vertical_strength = y_offset < 0 ? -y_offset : y_offset;
        3. Decisionhorizontal_strength >= vertical_strength
          True
            1. Executecolumn_delta = x_offset < 0 ? -1 : 1;
          False
            1. Executerow_delta = y_offset < 0 ? 1 : -1;
      False

      Continue after this decision.

  7. Decision(column_delta != 0 || row_delta != 0) && now_ms - boulder_dash_last_move_at >= BOULDER_DASH_MOVE_REPEAT_MS
    True
      1. ExecutetryMoveBoulderDashPlayer(column_delta, row_delta, hold_a_to_stay, now_ms);
      2. Executeboulder_dash_last_move_at = now_ms;
    False

    Continue after this decision.

  8. Decisionnow_ms - boulder_dash_last_gravity_at >= BOULDER_DASH_GRAVITY_MS
    True
      1. ExecuteupdateBoulderDashGravity();
      2. Executeboulder_dash_last_gravity_at = now_ms;
    False

    Continue after this decision.

Read original function source
void updateBoulderDash(int x_offset, int y_offset, bool valid, bool left, bool right,
                       bool hold_a_to_stay, uint32_t now_ms)
{
    if (!boulder_dash_running) return;
    if (boulder_dash_state == BOULDER_DASH_LEVEL_FLASH) {
        const uint32_t flash_elapsed_ms = now_ms - boulder_dash_level_flash_started_at;
        boulder_dash_level_flash_light =
            (flash_elapsed_ms / BOULDER_DASH_LEVEL_FLASH_INTERVAL_MS) % 2U == 0U;
        if (flash_elapsed_ms >= BOULDER_DASH_LEVEL_FLASH_DURATION_MS) {
            boulder_dash_state = BOULDER_DASH_COMPLETE;
        }
        return;
    }
    if (boulder_dash_state != BOULDER_DASH_PLAYING) return;

    int column_delta = 0;
    int row_delta = 0;
    if (left != right) {
        column_delta = left ? -1 : 1;
    } else if (valid &&
               (x_offset >= BOULDER_DASH_JOYSTICK_THRESHOLD ||
                x_offset <= -BOULDER_DASH_JOYSTICK_THRESHOLD ||
                y_offset >= BOULDER_DASH_JOYSTICK_THRESHOLD ||
                y_offset <= -BOULDER_DASH_JOYSTICK_THRESHOLD)) {
        const int horizontal_strength = x_offset < 0 ? -x_offset : x_offset;
        const int vertical_strength = y_offset < 0 ? -y_offset : y_offset;
        if (horizontal_strength >= vertical_strength) {
            column_delta = x_offset < 0 ? -1 : 1;
        } else {
            // This project's calibrated joystick reports negative Y when pushed
            // physically down, while cave rows increase toward the bottom.
            row_delta = y_offset < 0 ? 1 : -1;
        }
    }

    if ((column_delta != 0 || row_delta != 0) &&
        now_ms - boulder_dash_last_move_at >= BOULDER_DASH_MOVE_REPEAT_MS) {
        tryMoveBoulderDashPlayer(column_delta, row_delta, hold_a_to_stay, now_ms);
        boulder_dash_last_move_at = now_ms;
    }
    if (now_ms - boulder_dash_last_gravity_at >= BOULDER_DASH_GRAVITY_MS) {
        updateBoulderDashGravity();
        boulder_dash_last_gravity_at = now_ms;
    }
}
drawBoulderDash() · source line 567
void drawBoulderDash(uint16_t *frame)

Calls into this documentation:

  1. Decisionframe == NULL
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Executechar score_text[18];
  3. Executechar diamond_text[18];
  4. Executechar level_text[24];
  5. Decisionboulder_dash_state == BOULDER_DASH_LEVEL_FLASH
    True
      1. Executeclear(frame, boulder_dash_level_flash_light ? COLOR_WHITE : COLOR_DARKBLUE);
      2. Exit this functionreturn;
    False

    Continue after this decision.

  6. Decisionboulder_dash_state == BOULDER_DASH_COMPLETE
    True
      1. Executeclear(frame, COLOR_DARKBLUE);
      2. Decisionboulder_dash_level_index + 1U == BOULDER_DASH_LEVEL_COUNT
        True
          1. Executedraw_text_centred(frame, LCD_WIDTH / 2, 48, "GAME COMPLETE", 2, COLOR_LIGHTGREEN);
        False
          1. Execute(void)snprintf(level_text, sizeof(level_text), "LEVEL %u COMPLETE", (unsigned)(boulder_dash_level_index + 1U));
          2. Executedraw_text_centred(frame, LCD_WIDTH / 2, 48, level_text, 2, COLOR_LIGHTGREEN);
      3. Execute(void)snprintf(score_text, sizeof(score_text), "SCORE %ld", (long)boulder_dash_score);
      4. Executedraw_text_centred(frame, LCD_WIDTH / 2, 82, score_text, 2, COLOR_WHITE);
      5. Executedraw_text_centred(frame, LCD_WIDTH / 2, 116, boulder_dash_level_index + 1U == BOULDER_DASH_LEVEL_COUNT ? "A/K LEVEL 1" : "A/K NEXT LEVEL", 1, COLOR_YELLOW);
      6. Exit this functionreturn;
    False

    Continue after this decision.

  7. Decisionboulder_dash_state == BOULDER_DASH_GAME_OVER
    True
      1. Executeclear(frame, COLOR_DARKBLUE);
      2. Executedraw_text_centred(frame, LCD_WIDTH / 2, 48, "GAME OVER", 2, COLOR_LIGHTCORAL);
      3. Execute(void)snprintf(score_text, sizeof(score_text), "SCORE %ld", (long)boulder_dash_score);
      4. Executedraw_text_centred(frame, LCD_WIDTH / 2, 82, score_text, 2, COLOR_WHITE);
      5. Executedraw_text_centred(frame, LCD_WIDTH / 2, 116, "A/K NEW GAME", 1, COLOR_YELLOW);
      6. Exit this functionreturn;
    False

    Continue after this decision.

  8. Executefill_rect(frame, 0, 0, LCD_WIDTH, BOULDER_DASH_STATUS_HEIGHT, COLOR_DARKBLUE);
  9. Execute(void)snprintf(level_text, sizeof(level_text), "BOULDER L%u", (unsigned)(boulder_dash_level_index + 1U));
  10. Executedraw_text(frame, 8, 4, level_text, 2, COLOR_WHITE);
  11. Decisionboulder_dash_state == BOULDER_DASH_CRUSHED
    True
      1. Executedraw_text(frame, 210, 3, "CRUSHED", 1, COLOR_LIGHTCORAL);
      2. Execute(void)snprintf(level_text, sizeof(level_text), "A RESET L %u", (unsigned)boulder_dash_lives);
      3. Executedraw_text(frame, 210, 13, level_text, 1, COLOR_YELLOW);
    False
      1. Execute(void)snprintf(score_text, sizeof(score_text), "S %ld", (long)boulder_dash_score);
      2. Execute(void)snprintf(diamond_text, sizeof(diamond_text), "D %u/%u", (unsigned)boulder_dash_diamonds_collected, (unsigned)boulder_dash_diamonds_required);
      3. Executedraw_text(frame, 210, 3, score_text, 1, COLOR_CYAN);
      4. Executedraw_text(frame, 260, 3, diamond_text, 1, COLOR_CYAN);
      5. Execute(void)snprintf(level_text, sizeof(level_text), "%s L %u", boulderDashExitOpen() ? "EXIT OPEN" : "EXIT LOCK", (unsigned)boulder_dash_lives);
      6. Executedraw_text(frame, 210, 13, level_text, 1, boulderDashExitOpen() ? COLOR_LIGHTGREEN : COLOR_LIGHTGREY);
  12. FOR loopint row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column

        Repeat body while the loop condition permits; then continue below.

          1. ExecutedrawBoulderDashTile(frame, column * BOULDER_DASH_TILE_SIZE, BOULDER_DASH_STATUS_HEIGHT + row * BOULDER_DASH_TILE_SIZE, boulder_dash_cave[row][column], boulderDashExitOpen());
  13. Decisionboulder_dash_state == BOULDER_DASH_PLAYING
    True
      1. Executeconst int player_x = boulder_dash_player_column * BOULDER_DASH_TILE_SIZE;
      2. Executeconst int player_y = BOULDER_DASH_STATUS_HEIGHT + boulder_dash_player_row * BOULDER_DASH_TILE_SIZE;
      3. ExecutedrawBoulderDashTile(frame, player_x, player_y, BOULDER_DASH_PLAYER, boulderDashExitOpen());
    False

    Continue after this decision.

Read original function source
void drawBoulderDash(uint16_t *frame)
{
    if (frame == NULL) return;

    char score_text[18];
    char diamond_text[18];
    char level_text[24];
    if (boulder_dash_state == BOULDER_DASH_LEVEL_FLASH) {
        clear(frame, boulder_dash_level_flash_light ? COLOR_WHITE : COLOR_DARKBLUE);
        return;
    }
    if (boulder_dash_state == BOULDER_DASH_COMPLETE) {
        clear(frame, COLOR_DARKBLUE);
        if (boulder_dash_level_index + 1U == BOULDER_DASH_LEVEL_COUNT) {
            draw_text_centred(frame, LCD_WIDTH / 2, 48, "GAME COMPLETE", 2, COLOR_LIGHTGREEN);
        } else {
            (void)snprintf(level_text, sizeof(level_text), "LEVEL %u COMPLETE",
                           (unsigned)(boulder_dash_level_index + 1U));
            draw_text_centred(frame, LCD_WIDTH / 2, 48, level_text, 2, COLOR_LIGHTGREEN);
        }
        (void)snprintf(score_text, sizeof(score_text), "SCORE %ld", (long)boulder_dash_score);
        draw_text_centred(frame, LCD_WIDTH / 2, 82, score_text, 2, COLOR_WHITE);
        draw_text_centred(frame, LCD_WIDTH / 2, 116,
                          boulder_dash_level_index + 1U == BOULDER_DASH_LEVEL_COUNT
                              ? "A/K LEVEL 1"
                              : "A/K NEXT LEVEL",
                          1, COLOR_YELLOW);
        return;
    }
    if (boulder_dash_state == BOULDER_DASH_GAME_OVER) {
        clear(frame, COLOR_DARKBLUE);
        draw_text_centred(frame, LCD_WIDTH / 2, 48, "GAME OVER", 2, COLOR_LIGHTCORAL);
        (void)snprintf(score_text, sizeof(score_text), "SCORE %ld", (long)boulder_dash_score);
        draw_text_centred(frame, LCD_WIDTH / 2, 82, score_text, 2, COLOR_WHITE);
        draw_text_centred(frame, LCD_WIDTH / 2, 116, "A/K NEW GAME", 1, COLOR_YELLOW);
        return;
    }

    fill_rect(frame, 0, 0, LCD_WIDTH, BOULDER_DASH_STATUS_HEIGHT, COLOR_DARKBLUE);
    (void)snprintf(level_text, sizeof(level_text), "BOULDER L%u",
                   (unsigned)(boulder_dash_level_index + 1U));
    draw_text(frame, 8, 4, level_text, 2, COLOR_WHITE);
    if (boulder_dash_state == BOULDER_DASH_CRUSHED) {
        draw_text(frame, 210, 3, "CRUSHED", 1, COLOR_LIGHTCORAL);
        (void)snprintf(level_text, sizeof(level_text), "A RESET  L %u",
                       (unsigned)boulder_dash_lives);
        draw_text(frame, 210, 13, level_text, 1, COLOR_YELLOW);
    } else {
        (void)snprintf(score_text, sizeof(score_text), "S %ld", (long)boulder_dash_score);
        (void)snprintf(diamond_text, sizeof(diamond_text), "D %u/%u",
                       (unsigned)boulder_dash_diamonds_collected,
                       (unsigned)boulder_dash_diamonds_required);
        draw_text(frame, 210, 3, score_text, 1, COLOR_CYAN);
        draw_text(frame, 260, 3, diamond_text, 1, COLOR_CYAN);
        (void)snprintf(level_text, sizeof(level_text), "%s  L %u",
                       boulderDashExitOpen() ? "EXIT OPEN" : "EXIT LOCK",
                       (unsigned)boulder_dash_lives);
        draw_text(frame, 210, 13, level_text,
                  1, boulderDashExitOpen() ? COLOR_LIGHTGREEN : COLOR_LIGHTGREY);
    }

    for (int row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            drawBoulderDashTile(frame, column * BOULDER_DASH_TILE_SIZE,
                                BOULDER_DASH_STATUS_HEIGHT + row * BOULDER_DASH_TILE_SIZE,
                                boulder_dash_cave[row][column], boulderDashExitOpen());
        }
    }
    if (boulder_dash_state == BOULDER_DASH_PLAYING) {
        const int player_x = boulder_dash_player_column * BOULDER_DASH_TILE_SIZE;
        const int player_y = BOULDER_DASH_STATUS_HEIGHT +
                             boulder_dash_player_row * BOULDER_DASH_TILE_SIZE;
        drawBoulderDashTile(frame, player_x, player_y, BOULDER_DASH_PLAYER,
                            boulderDashExitOpen());
    }
}
Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "boulder_dash.h"

#include "game_colors.h"
#include "game_graphics.h"
#include "PET2001_font.h"
#include "screen_transition.h"

#include "esp_random.h"

#include <stdio.h>
#include <string.h>

// -----------------------------------------------------------------------------
// Boulder Dash frame: a 20 x 9 cave of native 16 x 16 cells fills the 320 x 144
// playfield.  The remaining 26 display rows form the fixed status strip.
//
// These one-bit masks are deliberately temporary built-in sprites.  Keeping them
// together makes the later artwork/resource layer a direct replacement, without
// changing the cave map or the game's screen integration.
// -----------------------------------------------------------------------------
#define BOULDER_DASH_TILE_SIZE 16
#define BOULDER_DASH_CAVE_COLUMNS 20
#define BOULDER_DASH_CAVE_ROWS 9
#define BOULDER_DASH_STATUS_HEIGHT 26
#define BOULDER_DASH_TILE_MASK_BYTES 32
#define BOULDER_DASH_LEVEL_COUNT 10U
#define BOULDER_DASH_LEVEL_PLACEMENT_ATTEMPTS 512U

// Visual tuning controls for the first playable cave.
// Keep gravity slower than movement so a player can see and react to each fall.
#define BOULDER_DASH_MOVE_REPEAT_MS 140U
#define BOULDER_DASH_GRAVITY_MS 320U
#define BOULDER_DASH_JOYSTICK_THRESHOLD 600
// Completion flash tuning: total length must remain a multiple of the interval
// so the sequence ends on the same dark-blue colour on every run.
#define BOULDER_DASH_LEVEL_FLASH_DURATION_MS 720U
#define BOULDER_DASH_LEVEL_FLASH_INTERVAL_MS 90U
// Level-start effects reuse the global transition renderer. Each new cave randomly
// selects one; input and gravity remain paused until its captured frame is complete.
#define BOULDER_DASH_LEVEL_REVEAL_MS 700U
#define BOULDER_DASH_LEVEL_REVEAL_PERCENT 100U
#define BOULDER_DASH_LEVEL_SLICE_COUNT 12U
#define BOULDER_DASH_LEVEL_SLICE_MS 650U
// Scoring rules: diamonds reward exploration; each previously untouched dirt
// tile costs one point exactly once, because digging turns it into empty space.
#define BOULDER_DASH_DIAMOND_POINTS 10
#define BOULDER_DASH_NEW_DIRT_PENALTY 1
#define BOULDER_DASH_STARTING_LIVES 3U

typedef enum {
    BOULDER_DASH_EMPTY,
    BOULDER_DASH_DIRT,
    BOULDER_DASH_STEEL,
    BOULDER_DASH_BOULDER,
    BOULDER_DASH_DIAMOND,
    BOULDER_DASH_PLAYER,
    BOULDER_DASH_EXIT,
} boulder_dash_tile_t;

// Level 1 is hand-authored. Levels 2-10 use their fixed seeds to produce the
// same cave on every replay, while these values tune their gradual difficulty.
typedef struct {
    uint32_t seed;
    uint8_t diamonds;
    uint8_t boulders;
    uint8_t steel_blocks;
} boulder_dash_level_definition_t;

static const boulder_dash_level_definition_t boulder_dash_levels[BOULDER_DASH_LEVEL_COUNT] = {
    {0U, 6U, 2U, 0U},
    {0x4c455632U, 8U, 3U, 12U},
    {0x4c455633U, 12U, 5U, 21U},
    {0x4c455634U, 14U, 4U, 26U},
    {0x4c455635U, 16U, 5U, 31U},
    {0x4c455636U, 18U, 6U, 36U},
    {0x4c455637U, 20U, 7U, 41U},
    {0x4c455638U, 22U, 8U, 46U},
    {0x4c455639U, 24U, 9U, 50U},
    {0x4c455a30U, 26U, 10U, 54U},
};

// Each sprite uses 16 rows of two bytes, with the most-significant bit at left.
static const uint8_t boulder_dash_dirt_mask[BOULDER_DASH_TILE_MASK_BYTES] = {
    0x00, 0x00, 0x10, 0x80, 0x00, 0x04, 0x42, 0x00, 0x00, 0x20, 0x08, 0x00,
    0x80, 0x10, 0x01, 0x00, 0x20, 0x04, 0x04, 0x40, 0x00, 0x02, 0x41, 0x00,
    0x08, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x00,
};

static const uint8_t boulder_dash_steel_mask[BOULDER_DASH_TILE_MASK_BYTES] = {
    0xff, 0xff, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81,
    0x99, 0x99, 0x81, 0x81, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x99, 0x99,
    0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0xff, 0xff,
};

static const uint8_t boulder_dash_boulder_mask[BOULDER_DASH_TILE_MASK_BYTES] = {
    0x03, 0xc0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe,
    0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x03, 0xc0,
};

static const uint8_t boulder_dash_diamond_mask[BOULDER_DASH_TILE_MASK_BYTES] = {
    0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0,
    0x1f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0,
    0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t boulder_dash_player_mask[BOULDER_DASH_TILE_MASK_BYTES] = {
    0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1b, 0xd8, 0x1f, 0xf8, 0x0f, 0xf0,
    0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc, 0x2d, 0xb4, 0x0c, 0x30,
    0x1c, 0x38, 0x38, 0x1c, 0x70, 0x0e, 0x60, 0x06,
};

static const uint8_t boulder_dash_exit_mask[BOULDER_DASH_TILE_MASK_BYTES] = {
    0x3f, 0xfc, 0x7f, 0xfe, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06,
    0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06,
    0x60, 0x06, 0x60, 0x06, 0x7f, 0xfe, 0x3f, 0xfc,
};

// Level 1 is deliberately a small teaching cave rather than a random tile test:
// dig from the upper-left start, collect all six diamonds, make a safe sideways
// boulder push, watch the supported boulder roll, then reach the lower-right exit.
// The later resource/level layer can replace this map without changing the rules.
static const boulder_dash_tile_t boulder_dash_level_one_cave[BOULDER_DASH_CAVE_ROWS]
                                                             [BOULDER_DASH_CAVE_COLUMNS] = {
    {BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_PLAYER, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_EMPTY, BOULDER_DASH_DIAMOND, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_BOULDER, BOULDER_DASH_EMPTY, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIAMOND, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIAMOND, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_EMPTY, BOULDER_DASH_BOULDER, BOULDER_DASH_EMPTY, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_EMPTY, BOULDER_DASH_DIAMOND, BOULDER_DASH_EMPTY, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIAMOND, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_STEEL, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIRT, BOULDER_DASH_DIAMOND, BOULDER_DASH_DIRT, BOULDER_DASH_EXIT, BOULDER_DASH_STEEL},
    {BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL, BOULDER_DASH_STEEL},
};

typedef enum {
    BOULDER_DASH_PLAYING,
    BOULDER_DASH_LEVEL_FLASH,
    BOULDER_DASH_CRUSHED,
    BOULDER_DASH_COMPLETE,
    BOULDER_DASH_GAME_OVER,
} boulder_dash_state_t;

static boulder_dash_tile_t boulder_dash_cave[BOULDER_DASH_CAVE_ROWS]
                                             [BOULDER_DASH_CAVE_COLUMNS];
static boulder_dash_state_t boulder_dash_state;
static int boulder_dash_player_column;
static int boulder_dash_player_row;
static uint8_t boulder_dash_diamonds_collected;
static uint8_t boulder_dash_diamonds_required;
static int32_t boulder_dash_score;
// Score and lives belong to the whole ten-level run, not one cave attempt.
static uint8_t boulder_dash_lives;
static uint32_t boulder_dash_last_move_at;
static uint32_t boulder_dash_last_gravity_at;
static uint32_t boulder_dash_now_ms;
static uint32_t boulder_dash_level_flash_started_at;
static bool boulder_dash_level_flash_light;
// Alternate the preferred roll side after each successful roll, preventing a
// symmetrical cave from always favouring its left-hand route.
static bool boulder_dash_roll_left_first;
static bool boulder_dash_running;
static uint8_t boulder_dash_level_index;
static uint32_t boulder_dash_level_random_state;
// One reusable PSRAM-backed transition owns the selected level-entry effect.
static screen_transition_t boulder_dash_level_transition;
// A reset builds the new cave first; drawBoulderDash captures that completed frame once.
static bool boulder_dash_level_transition_pending;
// True selects the shuffled 8 x 8 reveal; false selects alternating horizontal slices.
static bool boulder_dash_level_reveal_selected;

static uint32_t boulderDashNextLevelRandom(void)
{
    // Tiny deterministic PRNG: its state begins from the level's fixed seed,
    // so the generated layouts do not vary between separate plays.
    boulder_dash_level_random_state = boulder_dash_level_random_state * 1664525U + 1013904223U;
    return boulder_dash_level_random_state;
}

static bool boulderDashIsReservedLevelCell(int row, int column)
{
    // Preserve an open, safe two-by-two area around the upper-left spawn and
    // lower-right exit, independent of generated barrier/item placement.
    return (row <= 2 && column <= 2) ||
           (row >= BOULDER_DASH_CAVE_ROWS - 3 &&
            column >= BOULDER_DASH_CAVE_COLUMNS - 3);
}

static bool boulderDashWalkableCaveIsConnected(void)
{
    // Each proposed steel block is accepted only if every remaining non-steel
    // tile can still be reached from the spawn. This prevents a generated wall
    // pattern from sealing off part of the cave before gems are added.
    bool visited[BOULDER_DASH_CAVE_ROWS][BOULDER_DASH_CAVE_COLUMNS] = {{false}};
    uint8_t pending_cells[BOULDER_DASH_CAVE_ROWS * BOULDER_DASH_CAVE_COLUMNS];
    uint16_t read_index = 0U;
    uint16_t write_index = 0U;

    pending_cells[write_index++] = BOULDER_DASH_CAVE_COLUMNS + 1U;
    visited[1][1] = true;
    while (read_index < write_index) {
        const uint8_t cell = pending_cells[read_index++];
        const int row = cell / BOULDER_DASH_CAVE_COLUMNS;
        const int column = cell % BOULDER_DASH_CAVE_COLUMNS;
        static const int row_offsets[4] = {-1, 1, 0, 0};
        static const int column_offsets[4] = {0, 0, -1, 1};

        for (int direction = 0; direction < 4; ++direction) {
            const int next_row = row + row_offsets[direction];
            const int next_column = column + column_offsets[direction];
            if (next_row < 0 || next_row >= BOULDER_DASH_CAVE_ROWS ||
                next_column < 0 || next_column >= BOULDER_DASH_CAVE_COLUMNS ||
                visited[next_row][next_column] ||
                boulder_dash_cave[next_row][next_column] == BOULDER_DASH_STEEL) {
                continue;
            }
            visited[next_row][next_column] = true;
            pending_cells[write_index++] =
                (uint8_t)(next_row * BOULDER_DASH_CAVE_COLUMNS + next_column);
        }
    }

    for (int row = 1; row < BOULDER_DASH_CAVE_ROWS - 1; ++row) {
        for (int column = 1; column < BOULDER_DASH_CAVE_COLUMNS - 1; ++column) {
            if (boulder_dash_cave[row][column] != BOULDER_DASH_STEEL &&
                !visited[row][column]) {
                return false;
            }
        }
    }
    return true;
}

static void placeProceduralLevelTiles(boulder_dash_tile_t tile, uint8_t count)
{
    uint8_t placed = 0U;
    uint16_t attempts = 0U;
    while (placed < count && attempts++ < BOULDER_DASH_LEVEL_PLACEMENT_ATTEMPTS) {
        const int row = 1 + (int)(boulderDashNextLevelRandom() %
                                  (BOULDER_DASH_CAVE_ROWS - 2));
        const int column = 1 + (int)(boulderDashNextLevelRandom() %
                                     (BOULDER_DASH_CAVE_COLUMNS - 2));
        if (boulderDashIsReservedLevelCell(row, column) ||
            boulder_dash_cave[row][column] != BOULDER_DASH_DIRT) {
            continue;
        }
        // New boulders begin on dirt rather than open space, so they do not
        // drop the instant the level begins.
        if (tile == BOULDER_DASH_BOULDER &&
            boulder_dash_cave[row + 1][column] != BOULDER_DASH_DIRT) {
            continue;
        }
        boulder_dash_cave[row][column] = tile;
        ++placed;
    }
}

static void buildProceduralBoulderDashLevel(const boulder_dash_level_definition_t *level)
{
    boulder_dash_level_random_state = level->seed;
    for (int row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            boulder_dash_cave[row][column] =
                row == 0 || row == BOULDER_DASH_CAVE_ROWS - 1 ||
                column == 0 || column == BOULDER_DASH_CAVE_COLUMNS - 1
                    ? BOULDER_DASH_STEEL
                    : BOULDER_DASH_DIRT;
        }
    }

    boulder_dash_cave[1][1] = BOULDER_DASH_PLAYER;
    boulder_dash_cave[1][2] = BOULDER_DASH_EMPTY;
    boulder_dash_cave[2][1] = BOULDER_DASH_EMPTY;
    boulder_dash_cave[2][2] = BOULDER_DASH_EMPTY;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 2][BOULDER_DASH_CAVE_COLUMNS - 2] =
        BOULDER_DASH_EXIT;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 2][BOULDER_DASH_CAVE_COLUMNS - 3] =
        BOULDER_DASH_EMPTY;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 3][BOULDER_DASH_CAVE_COLUMNS - 2] =
        BOULDER_DASH_EMPTY;
    boulder_dash_cave[BOULDER_DASH_CAVE_ROWS - 3][BOULDER_DASH_CAVE_COLUMNS - 3] =
        BOULDER_DASH_EMPTY;

    uint8_t steel_placed = 0U;
    uint16_t attempts = 0U;
    while (steel_placed < level->steel_blocks &&
           attempts++ < BOULDER_DASH_LEVEL_PLACEMENT_ATTEMPTS) {
        const int row = 1 + (int)(boulderDashNextLevelRandom() %
                                  (BOULDER_DASH_CAVE_ROWS - 2));
        const int column = 1 + (int)(boulderDashNextLevelRandom() %
                                     (BOULDER_DASH_CAVE_COLUMNS - 2));
        if (boulderDashIsReservedLevelCell(row, column) ||
            boulder_dash_cave[row][column] != BOULDER_DASH_DIRT) {
            continue;
        }
        boulder_dash_cave[row][column] = BOULDER_DASH_STEEL;
        if (boulderDashWalkableCaveIsConnected()) {
            ++steel_placed;
        } else {
            boulder_dash_cave[row][column] = BOULDER_DASH_DIRT;
        }
    }

    placeProceduralLevelTiles(BOULDER_DASH_DIAMOND, level->diamonds);
    placeProceduralLevelTiles(BOULDER_DASH_BOULDER, level->boulders);
}

static void resetBoulderDashCave(uint32_t now_ms, bool reset_run_score)
{
    const boulder_dash_level_definition_t *const level =
        &boulder_dash_levels[boulder_dash_level_index];
    if (boulder_dash_level_index == 0U) {
        memcpy(boulder_dash_cave, boulder_dash_level_one_cave, sizeof(boulder_dash_cave));
    } else {
        buildProceduralBoulderDashLevel(level);
    }
    boulder_dash_diamonds_collected = 0U;
    boulder_dash_diamonds_required = 0U;
    if (reset_run_score) boulder_dash_score = 0;
    boulder_dash_roll_left_first = true;

    // The player is stored as coordinates rather than a map tile so the tile
    // beneath them remains available for boulders and other future interactions.
    for (int row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            if (boulder_dash_cave[row][column] == BOULDER_DASH_PLAYER) {
                boulder_dash_player_column = column;
                boulder_dash_player_row = row;
                boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
            } else if (boulder_dash_cave[row][column] == BOULDER_DASH_DIAMOND) {
                ++boulder_dash_diamonds_required;
            }
        }
    }

    boulder_dash_state = BOULDER_DASH_PLAYING;
    boulder_dash_now_ms = now_ms;
    boulder_dash_last_move_at = now_ms;
    boulder_dash_last_gravity_at = now_ms;
    // Choose independently for every initial cave, retry, next level, and new game.
    boulder_dash_level_reveal_selected = (esp_random() & 1U) == 0U;
    boulder_dash_level_transition_pending = true;
}

static void boulderDashCrushPlayer(void)
{
    // A loss always consumes one of the run's lives. The level remains ready
    // for an A/K restart while a life remains; the third loss ends the run.
    if (boulder_dash_lives > 0U) --boulder_dash_lives;
    boulder_dash_state = boulder_dash_lives == 0U
                             ? BOULDER_DASH_GAME_OVER
                             : BOULDER_DASH_CRUSHED;
}

static void drawBoulderDashTile(uint16_t *frame, int x, int y, boulder_dash_tile_t tile,
                                bool exit_open)
{
    switch (tile) {
        case BOULDER_DASH_EMPTY:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
            break;
        case BOULDER_DASH_DIRT:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_SADDLEBROWN);
            draw_bitmap_scaled(frame, x, y, boulder_dash_dirt_mask, 16, 16, 16, 16, COLOR_PERU);
            break;
        case BOULDER_DASH_STEEL:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_DARKSLATEGRAY);
            draw_bitmap_scaled(frame, x, y, boulder_dash_steel_mask, 16, 16, 16, 16, COLOR_LIGHTGREY);
            break;
        case BOULDER_DASH_BOULDER:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
            draw_bitmap_scaled(frame, x, y, boulder_dash_boulder_mask, 16, 16, 16, 16, COLOR_SLATEGRAY);
            break;
        case BOULDER_DASH_DIAMOND:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_DARKBLUE);
            draw_bitmap_scaled(frame, x, y, boulder_dash_diamond_mask, 16, 16, 16, 16, COLOR_CYAN);
            break;
        case BOULDER_DASH_PLAYER:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE, COLOR_BLACK);
            draw_bitmap_scaled(frame, x, y, boulder_dash_player_mask, 16, 16, 16, 16, COLOR_ORANGE);
            break;
        case BOULDER_DASH_EXIT:
            fill_rect(frame, x, y, BOULDER_DASH_TILE_SIZE, BOULDER_DASH_TILE_SIZE,
                      exit_open ? COLOR_DARKGREEN : COLOR_DARKRED);
            draw_bitmap_scaled(frame, x, y, boulder_dash_exit_mask, 16, 16, 16, 16,
                               exit_open ? COLOR_YELLOW : COLOR_LIGHTGREY);
            break;
    }
}

static bool boulderDashExitOpen(void)
{
    return boulder_dash_diamonds_collected >= boulder_dash_diamonds_required;
}

static void tryMoveBoulderDashPlayer(int column_delta, int row_delta, bool hold_a_to_stay,
                                     uint32_t now_ms)
{
    if (boulder_dash_state != BOULDER_DASH_PLAYING) return;

    const int next_column = boulder_dash_player_column + column_delta;
    const int next_row = boulder_dash_player_row + row_delta;
    if (next_column < 0 || next_column >= BOULDER_DASH_CAVE_COLUMNS ||
        next_row < 0 || next_row >= BOULDER_DASH_CAVE_ROWS) return;

    boulder_dash_tile_t *const destination = &boulder_dash_cave[next_row][next_column];
    if (*destination == BOULDER_DASH_STEEL) return;
    if (*destination == BOULDER_DASH_BOULDER) {
        // Rocks can only be pushed sideways, and only into an already empty
        // cell. Dirt, diamonds, exits, and vertical pushes remain blocked.
        // Holding A makes this a careful push: the rock moves, but the player
        // remains in place. Without A, the player follows into the old rock tile.
        const int push_column = next_column + column_delta;
        if (row_delta != 0 || push_column < 0 || push_column >= BOULDER_DASH_CAVE_COLUMNS ||
            boulder_dash_cave[next_row][push_column] != BOULDER_DASH_EMPTY) return;
        boulder_dash_cave[next_row][push_column] = BOULDER_DASH_BOULDER;
        *destination = BOULDER_DASH_EMPTY;
        if (!hold_a_to_stay) {
            boulder_dash_player_column = next_column;
            boulder_dash_player_row = next_row;
        }
        return;
    }
    if (*destination == BOULDER_DASH_EXIT) {
        if (boulderDashExitOpen()) {
            boulder_dash_state = BOULDER_DASH_LEVEL_FLASH;
            boulder_dash_level_flash_started_at = now_ms;
            boulder_dash_level_flash_light = true;
        }
        return;
    }

    // Dirt disappears as it is crossed; diamonds do too, while adding to the
    // count needed to unlock the exit. Empty tiles cost nothing after their
    // first digging pass.
    if (*destination == BOULDER_DASH_DIRT) {
        boulder_dash_score -= BOULDER_DASH_NEW_DIRT_PENALTY;
    } else if (*destination == BOULDER_DASH_DIAMOND) {
        ++boulder_dash_diamonds_collected;
        boulder_dash_score += BOULDER_DASH_DIAMOND_POINTS;
    }
    *destination = BOULDER_DASH_EMPTY;
    boulder_dash_player_column = next_column;
    boulder_dash_player_row = next_row;
}

static bool tryRollBoulder(int row, int column, int direction)
{
    const int side_column = column + direction;
    const int diagonal_row = row + 1;
    if (side_column < 0 || side_column >= BOULDER_DASH_CAVE_COLUMNS) return false;

    // A player beside the boulder blocks its path. A player in the diagonal
    // destination is struck by the rolling boulder just like a falling one.
    if (boulder_dash_player_row == row && boulder_dash_player_column == side_column) return false;
    if (boulder_dash_cave[row][side_column] != BOULDER_DASH_EMPTY) return false;
    if (boulder_dash_player_row == diagonal_row &&
        boulder_dash_player_column == side_column) {
        boulder_dash_cave[diagonal_row][side_column] = BOULDER_DASH_BOULDER;
        boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
        boulderDashCrushPlayer();
        return true;
    }
    if (boulder_dash_cave[diagonal_row][side_column] != BOULDER_DASH_EMPTY) return false;

    boulder_dash_cave[diagonal_row][side_column] = BOULDER_DASH_BOULDER;
    boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
    boulder_dash_roll_left_first = !boulder_dash_roll_left_first;
    return true;
}

static void updateBoulderDashGravity(void)
{
    // Bottom-up processing prevents a boulder from falling multiple cells in a
    // single gravity tick after it enters a new empty cell.
    for (int row = BOULDER_DASH_CAVE_ROWS - 2; row >= 0; --row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            if (boulder_dash_cave[row][column] != BOULDER_DASH_BOULDER) continue;

            const int below_row = row + 1;
            // A player directly underneath temporarily supports the boulder.
            // This permits digging sideways beneath it; once the player moves
            // clear, the empty cell below makes the boulder fall next tick.
            // Diagonal rolling remains dangerous and is handled in tryRollBoulder.
            if (boulder_dash_player_row == below_row &&
                boulder_dash_player_column == column) continue;
            const boulder_dash_tile_t below_tile = boulder_dash_cave[below_row][column];
            if (below_tile == BOULDER_DASH_EMPTY) {
                boulder_dash_cave[below_row][column] = BOULDER_DASH_BOULDER;
                boulder_dash_cave[row][column] = BOULDER_DASH_EMPTY;
                continue;
            }

            // Only round boulders and diamonds provide a surface a boulder can
            // roll from. Dirt and steel deliberately hold it still.
            if (below_tile != BOULDER_DASH_BOULDER && below_tile != BOULDER_DASH_DIAMOND) {
                continue;
            }
            const int first_direction = boulder_dash_roll_left_first ? -1 : 1;
            if (tryRollBoulder(row, column, first_direction) ||
                tryRollBoulder(row, column, -first_direction)) {
                if (boulder_dash_state != BOULDER_DASH_PLAYING) return;
            }
        }
    }
}

void startBoulderDash(uint32_t now_ms)
{
    // A stopped game normally released this already; keep a restarted module leak-free too.
    screenTransitionDeinitialize(&boulder_dash_level_transition);
    boulder_dash_running = true;
    boulder_dash_level_index = 0U;
    boulder_dash_lives = BOULDER_DASH_STARTING_LIVES;
    resetBoulderDashCave(now_ms, true);
}

void stopBoulderDash(void)
{
    // The shared effects retain PSRAM snapshots only while Boulder Dash is open.
    screenTransitionDeinitialize(&boulder_dash_level_transition);
    boulder_dash_level_transition_pending = false;
    boulder_dash_running = false;
}

void boulderDashAction(bool reset_cave, uint32_t now_ms)
{
    // During normal play A is held as the careful-push modifier. A/K resets
    // after death; after completion it advances through all ten levels. The
    // success flash is always allowed to finish before either action occurs.
    if (boulder_dash_running && reset_cave &&
        boulder_dash_state == BOULDER_DASH_CRUSHED) {
        resetBoulderDashCave(now_ms, false);
    } else if (boulder_dash_running && reset_cave &&
               boulder_dash_state == BOULDER_DASH_COMPLETE) {
        boulder_dash_level_index =
            (uint8_t)((boulder_dash_level_index + 1U) % BOULDER_DASH_LEVEL_COUNT);
        resetBoulderDashCave(now_ms, false);
    } else if (boulder_dash_running && reset_cave &&
               boulder_dash_state == BOULDER_DASH_GAME_OVER) {
        boulder_dash_level_index = 0U;
        boulder_dash_lives = BOULDER_DASH_STARTING_LIVES;
        resetBoulderDashCave(now_ms, true);
    }
}

void updateBoulderDash(int x_offset, int y_offset, bool valid, bool left, bool right,
                       bool hold_a_to_stay, uint32_t now_ms)
{
    if (!boulder_dash_running) return;
    boulder_dash_now_ms = now_ms;
    // A level must remain visually and physically frozen until its entry effect finishes.
    if (screenRevealActive(&boulder_dash_level_transition)) {
        if (screenRevealComplete(&boulder_dash_level_transition)) {
            screenRevealReset(&boulder_dash_level_transition);
        }
        return;
    }
    if (screenSliceActive(&boulder_dash_level_transition)) {
        if (screenSliceComplete(&boulder_dash_level_transition)) {
            screenSliceReset(&boulder_dash_level_transition);
        }
        return;
    }
    if (boulder_dash_level_transition_pending) return;
    if (boulder_dash_state == BOULDER_DASH_LEVEL_FLASH) {
        const uint32_t flash_elapsed_ms = now_ms - boulder_dash_level_flash_started_at;
        boulder_dash_level_flash_light =
            (flash_elapsed_ms / BOULDER_DASH_LEVEL_FLASH_INTERVAL_MS) % 2U == 0U;
        if (flash_elapsed_ms >= BOULDER_DASH_LEVEL_FLASH_DURATION_MS) {
            boulder_dash_state = BOULDER_DASH_COMPLETE;
        }
        return;
    }
    if (boulder_dash_state != BOULDER_DASH_PLAYING) return;

    int column_delta = 0;
    int row_delta = 0;
    if (left != right) {
        column_delta = left ? -1 : 1;
    } else if (valid &&
               (x_offset >= BOULDER_DASH_JOYSTICK_THRESHOLD ||
                x_offset <= -BOULDER_DASH_JOYSTICK_THRESHOLD ||
                y_offset >= BOULDER_DASH_JOYSTICK_THRESHOLD ||
                y_offset <= -BOULDER_DASH_JOYSTICK_THRESHOLD)) {
        const int horizontal_strength = x_offset < 0 ? -x_offset : x_offset;
        const int vertical_strength = y_offset < 0 ? -y_offset : y_offset;
        if (horizontal_strength >= vertical_strength) {
            column_delta = x_offset < 0 ? -1 : 1;
        } else {
            // This project's calibrated joystick reports negative Y when pushed
            // physically down, while cave rows increase toward the bottom.
            row_delta = y_offset < 0 ? 1 : -1;
        }
    }

    if ((column_delta != 0 || row_delta != 0) &&
        now_ms - boulder_dash_last_move_at >= BOULDER_DASH_MOVE_REPEAT_MS) {
        tryMoveBoulderDashPlayer(column_delta, row_delta, hold_a_to_stay, now_ms);
        boulder_dash_last_move_at = now_ms;
    }
    if (now_ms - boulder_dash_last_gravity_at >= BOULDER_DASH_GRAVITY_MS) {
        updateBoulderDashGravity();
        boulder_dash_last_gravity_at = now_ms;
    }
}

void drawBoulderDash(uint16_t *frame)
{
    if (frame == NULL) return;

    // Once started, the transition redraws its captured cave instead of live gameplay.
    if (screenRevealActive(&boulder_dash_level_transition)) {
        screenRevealDraw(&boulder_dash_level_transition, frame, boulder_dash_now_ms);
        return;
    }
    if (screenSliceActive(&boulder_dash_level_transition)) {
        screenSliceDraw(&boulder_dash_level_transition, frame, boulder_dash_now_ms);
        return;
    }

    char score_text[18];
    char diamond_text[18];
    char level_text[24];
    if (boulder_dash_state == BOULDER_DASH_LEVEL_FLASH) {
        clear(frame, boulder_dash_level_flash_light ? COLOR_WHITE : COLOR_DARKBLUE);
        return;
    }
    if (boulder_dash_state == BOULDER_DASH_COMPLETE) {
        clear(frame, COLOR_DARKBLUE);
        if (boulder_dash_level_index + 1U == BOULDER_DASH_LEVEL_COUNT) {
            drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 48,
                                              "GAME COMPLETE", COLOR_LIGHTGREEN, 2);
        } else {
            (void)snprintf(level_text, sizeof(level_text), "LEVEL %u COMPLETE",
                           (unsigned)(boulder_dash_level_index + 1U));
            drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 48,
                                              level_text, COLOR_LIGHTGREEN, 2);
        }
        (void)snprintf(score_text, sizeof(score_text), "SCORE %ld", (long)boulder_dash_score);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 82,
                                          score_text, COLOR_WHITE, 2);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 116,
                                          boulder_dash_level_index + 1U == BOULDER_DASH_LEVEL_COUNT
                                              ? "A/K LEVEL 1"
                                              : "A/K NEXT LEVEL",
                                          COLOR_YELLOW, 1);
        return;
    }
    if (boulder_dash_state == BOULDER_DASH_GAME_OVER) {
        clear(frame, COLOR_DARKBLUE);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 48,
                                          "GAME OVER", COLOR_LIGHTCORAL, 2);
        (void)snprintf(score_text, sizeof(score_text), "SCORE %ld", (long)boulder_dash_score);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 82,
                                          score_text, COLOR_WHITE, 2);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 116,
                                          "A/K NEW GAME", COLOR_YELLOW, 1);
        return;
    }

    fill_rect(frame, 0, 0, LCD_WIDTH, BOULDER_DASH_STATUS_HEIGHT, COLOR_DARKBLUE);
    (void)snprintf(level_text, sizeof(level_text), "LEVEL %u",
                   (unsigned)(boulder_dash_level_index + 1U));
    drawPet2001TextTransparent(frame, 8, 4, level_text, COLOR_WHITE, 2);
    if (boulder_dash_state == BOULDER_DASH_CRUSHED) {
        drawPet2001TextTransparent(frame, 210, 3, "CRUSHED", COLOR_LIGHTCORAL, 1);
        (void)snprintf(level_text, sizeof(level_text), "A RESET  L %u",
                       (unsigned)boulder_dash_lives);
        drawPet2001TextTransparent(frame, 210, 13, level_text, COLOR_YELLOW, 1);
    } else {
        (void)snprintf(score_text, sizeof(score_text), "S %ld", (long)boulder_dash_score);
        (void)snprintf(diamond_text, sizeof(diamond_text), "D %u/%u",
                       (unsigned)boulder_dash_diamonds_collected,
                       (unsigned)boulder_dash_diamonds_required);
        drawPet2001TextTransparent(frame, 210, 3, score_text, COLOR_CYAN, 1);
        drawPet2001TextTransparent(frame, 260, 3, diamond_text, COLOR_CYAN, 1);
        (void)snprintf(level_text, sizeof(level_text), "%s  L%u",
                       boulderDashExitOpen() ? "EXIT OPEN" : "EXIT LOCK",
                       (unsigned)boulder_dash_lives);
        drawPet2001TextTransparent(frame, 210, 13, level_text,
                                  boulderDashExitOpen() ? COLOR_LIGHTGREEN : COLOR_LIGHTGREY, 1);
    }

    for (int row = 0; row < BOULDER_DASH_CAVE_ROWS; ++row) {
        for (int column = 0; column < BOULDER_DASH_CAVE_COLUMNS; ++column) {
            drawBoulderDashTile(frame, column * BOULDER_DASH_TILE_SIZE,
                                BOULDER_DASH_STATUS_HEIGHT + row * BOULDER_DASH_TILE_SIZE,
                                boulder_dash_cave[row][column], boulderDashExitOpen());
        }
    }
    if (boulder_dash_state == BOULDER_DASH_PLAYING) {
        const int player_x = boulder_dash_player_column * BOULDER_DASH_TILE_SIZE;
        const int player_y = BOULDER_DASH_STATUS_HEIGHT +
                             boulder_dash_player_row * BOULDER_DASH_TILE_SIZE;
        drawBoulderDashTile(frame, player_x, player_y, BOULDER_DASH_PLAYER,
                            boulderDashExitOpen());
    }
    if (boulder_dash_level_transition_pending) {
        // The cave and PET status strip above are the completed destination captured by
        // the existing global effect. If PSRAM is unavailable, leave this full frame visible.
        const bool started = boulder_dash_level_reveal_selected
            ? screenRevealStart(&boulder_dash_level_transition, frame,
                                boulder_dash_now_ms, BOULDER_DASH_LEVEL_REVEAL_MS,
                                BOULDER_DASH_LEVEL_REVEAL_PERCENT)
            : screenSliceStart(&boulder_dash_level_transition, frame,
                               boulder_dash_now_ms, BOULDER_DASH_LEVEL_SLICE_COUNT,
                               BOULDER_DASH_LEVEL_SLICE_MS);
        boulder_dash_level_transition_pending = false;
        if (started) {
            if (boulder_dash_level_reveal_selected) {
                screenRevealDraw(&boulder_dash_level_transition, frame,
                                 boulder_dash_now_ms);
            } else {
                screenSliceDraw(&boulder_dash_level_transition, frame,
                                boulder_dash_now_ms);
            }
        }
    }
}