Level 4 – Layered Bugs (≈ 10 minutes, stretch)
Concepts: layered bugs, unexpected control flow, combining debugger tools, fixing bugs without breaking other behavior.
This Level uses a small “level loader” that:
- Reads a level number from a (fake) string.
- Loads some enemy counts.
- Computes total difficulty.
The code has:
- A runtime bug (exception).
- A logic bug.
- A bug where stepping into another file is useful.
1. Setup the files
We’ll add two more files:
LevelLoader.javaInputParser.java
InputParser.java
public class InputParser {
public static int parseLevel(String input) {
String[] parts = input.split(":");
String numberPart = parts[1];
return Integer.parseInt(numberPart);
}
}
LevelLoader.java
public class LevelLoader {
public static int[] loadEnemiesForLevel(int level) {
if (level == 1) {
return new int[] {2, 3};
} else if (level == 2) {
return new int[] {4, 4, 5};
} else if (level == 3) {
return new int[] {10};
} else {
return null;
}
}
public static int computeDifficulty(int[] enemies) {
int enemyCount = (enemies == null) ? 0 : enemies.length;
int difficulty = 0;
for (int i = 0; i <= enemies.length; i++) {
difficulty += enemies[i] * (i + 1);
}
return difficulty;
}
}
Update Main.java
Add this method to the bottom of Main (inside the class, after printPlayerStats):
private static void demoLevels() {
System.out.println("=== Level Loader Demo ===");
String input = "level: 4";
System.out.println("Parsing input: \"" + input + "\"");
int level = InputParser.parseLevel(input);
System.out.println("Parsed level: " + level);
int[] enemies = LevelLoader.loadEnemiesForLevel(level);
int enemyCount = (enemies == null) ? 0 : enemies.length;
int difficulty = LevelLoader.computeDifficulty(enemies);
System.out.println("Total difficulty for level " + level + ": " + difficulty);
}
enemyCount is there so you can inspect length in the debugger (OnlineGDB does not show array length reliably).
Then, in main, after the mystery player block, add:
demoLevels();
Make sure Main.java now:
- Uses
Player,ScoreUtils,LevelLoader, andInputParser.
2. Run and observe
- Open
Main.java. - Click Run.
Expected symptoms:
- The scoreboard section should behave as in Level 3 (assuming you fixed it).
- The Level Loader demo will likely:
- Throw a
NumberFormatExceptionorNullPointerException. - Or print a strange difficulty.
- Throw a
Look at:
- The exception type.
- The stack trace: which method and line caused it?
3. Step through the layered flow
Use the debugger to trace the whole path:
- Set a breakpoint at the first line of
demoLevels. - Click Debug.
- Click the green Start button.
- When paused:
- Step Over the print statements.
- Use Step Into on
InputParser.parseLevel(input).
Inside parseLevel:
- Inspect
input,parts, andnumberPart. - Step line-by-line and identify exactly where and why the first failure happens.
Once you understand the problem, stop debugging and fix parseLevel to:
- Validate the input format.
- Trim whitespace.
- Return a reasonable default (for example
1) or throw a clearer exception.
Run again with the debugger to confirm the parsing step works.
4. Follow the next bug after parse is fixed
Next, set a breakpoint on:
int[] enemies = LevelLoader.loadEnemiesForLevel(level);
- Debug again and Step Into
LevelLoader.loadEnemiesForLevel. - For the given
level, see which branch runs and what it returns. - Fix the null issue you observe first.
- Re-run Debug and Start.
- Step back to
demoLevelsand then Step IntocomputeDifficulty.
Inside computeDifficulty (only after the null-related issue is fixed):
- Watch the values of
i,enemyCount(the localintincomputeDifficulty), anddifficulty. - See what happens when
ireaches the same value asenemyCount. - Use that to isolate the loop issue.
Fix the bugs by:
- Making
loadEnemiesForLevelreturn a non‑null array, even for unknown levels (for example, an emptyint[]). - Adjusting the
forloop incomputeDifficultyso it:- Does not go out of bounds.
- Handles
enemiesbeing null or empty safely.
Re‑run and confirm:
- No exceptions occur.
- The printed difficulty matches your expectations.
5. Avoid introducing new bugs
After each fix, re‑run the whole program, not just the Level Loader demo:
- Check that:
- The scoreboard output (from Level 3) still looks correct.
- No new exceptions appear.
This is a realistic part of debugging:
- Fix one bug.
- Run the full program.
- Make sure you didn’t break something else.
6. Reflection (Level 4)
Short prompts:
- What kinds of bugs did you see in this Level (compile‑time, runtime, logic)?
- How did stepping into helper methods (
parseLevel,loadEnemiesForLevel,computeDifficulty) help? - What habits can help avoid layered bugs (e.g., validating inputs, returning empty collections instead of null)?
You can compare your fixes to the suggested ones in Solutions & Fixes.