Escape the Debug Dungeon

Build a Python terminal adventure with rooms, inventory, and input validation.

Introduction

30 Second Summary

Games become frustrating when they misunderstand a command or stop after one wrong move. Clear feedback keeps the player exploring.

In this project, you will build a playable terminal adventure with Python. You will debug its one-turn limitation before expanding it into a complete dungeon.

What You'll Build

When the game is complete, you can demonstrate a full escape from the first room description to the final victory message.

By the end of this project, you'll have:

  • A playable command-line adventure that responds when you inspect rooms or travel through the dungeon.
  • Resilient command handling that gives unexpected input a clear response while keeping the game alive.
  • A multi-room escape whose locations come from structured game data. Your player can collect the key before unlocking the final gate.
  • Secret Mission: Turn the escape into a race by adding a countdown lantern.

Are there any prerequisites?

Your existing Python installation provides the runtime for this project. Your existing Visual Studio Code installation provides the Windows workspace.

Before We Start

Before any code is written, take a moment to commit to the game you are creating. Building Escape the Debug Dungeon from your own plan helps you practise turning a clear goal into a complete program.

Verify Your Python Workspace

Your dungeon needs a reliable path from saved code to the Python runtime that executes it. That path is still unproven on your machine.

This step connects Visual Studio Code to the escape-debug-dungeon workspace. The integrated PowerShell terminal then confirms that your first saved script can run.

In this step, get ready to:
  • Open escape-debug-dungeon as your Visual Studio Code workspace.
  • Create the dungeon_game.py project file.
  • Prove that the workspace can execute a Python script.
Create the workspace and project file

A workspace keeps your code files in one named folder. Its integrated terminal starts from that same folder.

  • Press the Windows key to open Windows search.
  • Type Visual Studio Code into the search field.
  • Press Enter to open the editor.

You should see the Visual Studio Code start screen.

  • Click File in the top menu bar.
  • Select Open Folder.
  • Choose Desktop in the Windows folder picker.
  • Create a folder named escape-debug-dungeon using the folder-creation control.
  • Select the escape-debug-dungeon folder.
  • Confirm the folder selection to open the workspace.

You should see escape-debug-dungeon as the open folder in Visual Studio Code.

  • Use the new-file control in the left sidebar to create dungeon_game.py inside escape-debug-dungeon.

You should see the empty dungeon_game.py file in the left sidebar.

Confirm the Python runtime

The integrated terminal connects your workspace to the runtime. A version check proves that the terminal can find the interpreter before your game depends on it.

  • Click View in the top menu bar.
  • Select Terminal.

You should see an integrated PowerShell terminal with escape-debug-dungeon as its current folder.

Before you run the check, what kind of output would prove that the terminal found the interpreter?

  • Check the installed runtime by running this command:
py -3 --version

What does this command prove?

The Windows launcher asks for the installed Python interpreter. Printing a version confirms that the runtime is available from this terminal.

✔️ I see the installed version

That confirms the workspace terminal can reach Python. Your editor and runtime are connected.

ⓧ The command is unavailable

The Windows launcher can be unavailable even when the default Python runtime works. The fallback command opens that runtime directly.

  • Start the default runtime by running this command:
python

What does this command prove?

The command starts Python in interactive mode. Seeing its input prompt confirms that PowerShell can reach the runtime.

  • Return to PowerShell by entering:
exit()

What does this code do?

This closes the interactive Python session. You return to the PowerShell prompt inside your workspace.

Still unable to reach Python?

Confirm that you are entering each command in the integrated PowerShell terminal. If neither check reaches the interpreter, use help me diagnose why Python is unavailable in my Visual Studio Code terminal.

Run the setup message

A tiny output message gives you a complete save-to-run test. If it appears in the terminal, the workspace folder and script path are working together.

  • Select dungeon_game.py from the left sidebar.
  • Add the setup message by pasting this code:
print("Dungeon setup ready")

What does this code do?

Python writes the text between the quotation marks to the terminal. This message gives you a clear success signal when the file runs.

  • Save dungeon_game.py.

Before you run the script, what message do you expect the terminal to print?

  • Verify the saved script by running this command in the integrated terminal:
python dungeon_game.py

What does this command do?

The runtime opens dungeon_game.py from the current workspace folder. It executes the file from top to bottom.

You should see Dungeon setup ready in the terminal. That is your first working dungeon signal from a saved file.

Don't see the setup message?

  • Confirm that dungeon_game.py is saved inside escape-debug-dungeon.
  • Check that the terminal prompt points to the escape-debug-dungeon folder.
  • Use help me fix why my saved dungeon_game.py file does not print its setup message if the output is still missing.

✔️ Awesome, I've got everything!

Great. Your saved dungeon_game.py file now runs from the workspace terminal.

ⓧ I'd like to double check the full code

Your complete dungeon_game.py file should contain this single line.

print("Dungeon setup ready")

Your workspace can now save and execute Python code. Next, you will turn that setup signal into the first playable version of the dungeon.

Build a One-Turn Dungeon Prototype

Your Python workspace now runs dungeon_game.py from the integrated terminal. That connection gives you a reliable place to turn your plan into working behavior.

Now you need an early playable result before adding the complete game structure.

This deliberately limited prototype reveals why one decision cannot support exploration. It also reveals why the player cannot recover from a bad command.

In this step, get ready to:
  • Create a prompt that normalizes one player command.
  • Respond to supported commands with conditional branches.
  • Document the limitation revealed by an unsupported command.
Build the first player turn

Player commands arrive as strings. Input normalization removes surrounding whitespace before converting the text to lowercase.

Conditional branches compare that consistent value against the commands your prototype supports.

  • Return to dungeon_game.py in Visual Studio Code.
  • Select the existing print("Dungeon setup ready") line.
  • Replace the selected line by pasting this prototype:
print("Escape the Debug Dungeon")
print("You stand at the dungeon entrance.")

command = input("\n> ").strip().lower()

if command == "look":
    print("The armory and gate are nearby.")
elif command == "go armory":
    print("You enter the armory.")
else:
    print("The dungeon ignores that command. Game over.")

What Does This Code Do?

  • The two print() calls establish the dungeon entrance.
  • The input() call reads one player command as a string.
  • The strip() method removes whitespace from both ends of the command.
  • The lower() method produces a lowercase copy for consistent matching.
  • The conditional chain routes the normalized command to one response.
  • Save dungeon_game.py.
  • Prepare to enter look when the prompt appears.
  • Run the one-turn prototype from the integrated terminal by using this command:
python dungeon_game.py

What Should I See?

You'll see the game title followed by the entrance description. After you enter look, you'll see The armory and gate are nearby.

Your first dungeon turn now responds to a real player command.

Seeing a Syntax Error?

  • Check that each print() line under a conditional branch is indented with four spaces.
  • Check that every if line ends with a colon.
  • Check that every elif line ends with a colon.
  • Check that the else line ends with a colon.
  • Help me find the syntax problem in my one-turn dungeon prototype.
Expose the one-turn limitation

The fallback branch handles input that does not match a supported command. This check reveals what the prototype does after that response.

Before you run the prototype again, do you expect another prompt after dance? The next run tests your prediction.

  • Prepare to enter dance when the prompt appears.
  • Test the unsupported command by running this command:
python dungeon_game.py

What Should I See?

You'll see The dungeon ignores that command. Game over. The PowerShell prompt returns immediately.

That shortfall is intentional. You have proved that a single conditional pass cannot recover from bad input.

Still Seeing the Setup Message?

  • Save the latest changes to dungeon_game.py.
  • Confirm the integrated terminal is inside the escape-debug-dungeon folder.
  • Help me understand why my terminal still runs the old dungeon setup code.
Record the limitation in code

A debugging note turns observed behavior into a concrete design requirement. Recording it now preserves the reason for the next design change.

  • Place your cursor on a blank line below the else branch in dungeon_game.py.
  • Record the observed limitation by adding this comment:
# Limitation: the game ends after one command, so the player cannot recover from bad input or explore.

Why Record the Limitation?

The comment captures the failure you observed. It gives the next design change a specific goal.

  • Save dungeon_game.py.

✔️ Awesome, I've got everything!

Great. Double-check that you saved dungeon_game.py with the limitation comment at the bottom.

ⓧ I'd like to double check the full code

Compare your saved dungeon_game.py with this complete one-turn prototype.

print("Escape the Debug Dungeon")
print("You stand at the dungeon entrance.")

command = input("\n> ").strip().lower()

if command == "look":
    print("The armory and gate are nearby.")
elif command == "go armory":
    print("You enter the armory.")
else:
    print("The dungeon ignores that command. Game over.")

# Limitation: the game ends after one command, so the player cannot recover from bad input or explore.

What Should Match?

  • The command variable stores normalized player input.
  • The conditional chain handles two supported commands plus one fallback path.
  • The final comment records the limitation you observed.

Before this final run, do you expect the new comment to change the game's output? The next run checks your prediction.

  • Prepare to enter dance when the prompt appears.
  • Verify the saved prototype from the integrated terminal by running this command:
python dungeon_game.py

What Should I See?

You'll see The dungeon ignores that command. Game over. The program then ends.

Your code comment records that exact behavior without changing the running game.

Did the Comment Cause an Error?

  • Confirm the limitation line begins with #.
  • Confirm the comment sits below the complete else branch.
  • Help me fix the limitation comment in my Python file.

Your prototype now proves where one-turn control flow falls short. Next, you'll make the dungeon recover from bad input without ending.

Make the Game Survive Bad Input

Your one-turn Python prototype accepts one normalized command. Every response still reaches the end of the program.

A command function gives input cleanup one clear home. A loop keeps the game alive until the player chooses to quit.

In this step, get ready to:
  • Create get_command() to normalize each command.
  • Keep command handling alive with a while True loop.
  • Test the full recovery sequence in one session.
Build the resilient command loop

The helper function applies the same cleanup to every command. The loop repeats the command handler until break deliberately ends it.

  • Switch back to dungeon_game.py in the editor.
  • Replace the existing contents of dungeon_game.py with this code:
def get_command():
    return input("\n> ").strip().lower()


print("Escape the Debug Dungeon")
print("You stand at the dungeon entrance.")

while True:
    command = get_command()

    if command == "look":
        print("The armory and gate are nearby.")
    elif command == "go armory":
        print("You enter the armory.")
    elif command == "quit":
        print("You leave the dungeon for another day.")
        break
    else:
        print("Unknown command. Try look or quit.")

What does this code do?

  • The get_command() function gives the input prompt one reusable home.
  • The returned string has surrounding whitespace removed. Uppercase letters also become lowercase.
  • The while True loop repeats the indented command handler after each response.
  • The quit branch uses break to end the loop deliberately.
  • The final else branch handles unsupported commands. The loop then asks for another command.
  • Save dungeon_game.py.
Test the recovery sequence

Before you run the game, the question is whether dance will stop the next prompt from appearing.

  • Start the updated game in the integrated terminal by running this command:
python dungeon_game.py

What does this command do?

The command launches your saved game from the workspace terminal. The process waits for each command until the loop reaches break.

  • Enter dance at the first prompt.
  • Enter look at the next prompt.
  • Enter quit at the final prompt.

After dance, you'll see Unknown command. Try look or quit. The game then shows another prompt.

After look, you'll see The armory and gate are nearby. After quit, you'll see You leave the dungeon for another day. before PowerShell returns.

That is the recovery loop working. One bad command no longer ends the session.

  • Explain aloud why repeating the command handler fixes the one-turn limitation.

Does the game still stop?

  • Check that command = get_command() is indented by four spaces under while True.
  • Check that the complete if chain is indented inside the loop.
  • Check that break is indented under the quit branch.
  • Help me debug the command loop.

✔️ Awesome, I've got everything!

Your command loop is saved. The game now recovers from unsupported input.

ⓧ I'd like to double check the full code

  • Compare dungeon_game.py with this saved version:
def get_command():
    return input("\n> ").strip().lower()


print("Escape the Debug Dungeon")
print("You stand at the dungeon entrance.")

while True:
    command = get_command()

    if command == "look":
        print("The armory and gate are nearby.")
    elif command == "go armory":
        print("You enter the armory.")
    elif command == "quit":
        print("You leave the dungeon for another day.")
        break
    else:
        print("Unknown command. Try look or quit.")

Your prototype now survives bad input. Next, you'll turn this command loop into a multi-room escape with navigation and inventory.

Build the Multi-Room Escape

Your command loop now survives bad input. However, each location still needs its own command branch.

As the dungeon grows, that approach becomes difficult to extend. A Python dictionary can give every room one home for its description and exits. Small functions can use that data while the loop manages the changing game state.

In this step, get ready to:
  • Model the dungeon rooms with descriptions and valid exits.
  • Track the player's location and key inventory.
  • Protect the gate and verify the complete escape path.
Model the dungeon with room data
  • In the open Visual Studio Code editor, switch back to dungeon_game.py.
  • Place your cursor above def get_command():.
  • Add the room map by pasting this code:
ROOMS = {
    "entrance": {
        "description": "You stand at the dungeon entrance. The armory and gate are nearby.",
        "exits": ["armory", "gate"],
    },
    "armory": {
        "description": "Dusty weapons cover the walls. A brass key rests on a table.",
        "exits": ["entrance"],
    },
    "gate": {
        "description": "Moonlight shines through the bars of the exit gate.",
        "exits": ["entrance"],
    },
}

What Does This Room Map Do?

  • ROOMS uses each room name as a key.
  • description stores the text shown when the player visits a room.
  • exits stores the destinations available from that room.
  • Save dungeon_game.py.
  • Check that the room data has valid Python syntax by running this command in the integrated terminal:
python dungeon_game.py

What Does This Check Prove?

Python reads the new room map before starting the existing prototype. Reaching the game prompt confirms that the dictionary has valid syntax.

  • Enter quit to end this test session.

You'll see You leave the dungeon for another day. before the terminal prompt returns.

Does the game stop before the prompt?

  • Check that each room name has matching quotation marks.
  • Check that every opening brace has a closing brace.
  • Use four spaces for each nested level.
  • Help me check the ROOMS dictionary for a Python syntax error.
  • Place your cursor below the get_command() function.
  • Add the room display and command guide by pasting this code:
def show_room(room_name):
    room = ROOMS[room_name]
    print(f"\nLocation: {room_name}")
    print(room["description"])
    print("Exits: " + ", ".join(room["exits"]))


def show_help():
    print("Commands: look, go <room>, take key, inventory, help, quit")

How Do These Helpers Use the Map?

  • show_room() retrieves the selected room from ROOMS.
  • join() turns the room's exit list into one readable line.
  • show_help() keeps the available instructions in one place.
  • Save dungeon_game.py.
  • Check the helper function syntax by running the game again:
python dungeon_game.py

What Does This Second Check Prove?

Python loads both helper definitions before reaching the existing command loop. Seeing the prompt confirms that their indentation and syntax are valid.

  • Enter quit to return to PowerShell.

Seeing an indentation error?

  • Align both def lines with the left edge of the file.
  • Indent each function body with four spaces.
  • Help me fix the indentation in my room helper functions.
Track inventory and player commands

The player now needs two pieces of changing state. current_room records the location. inventory records collected items.

  • Select the existing program from print("Escape the Debug Dungeon") through print("Unknown command. Try look or quit.").
  • Replace the selected program with this first version of play():
def play():
    current_room = "entrance"
    inventory = []

    print("Escape the Debug Dungeon")
    print("Find the key and unlock the gate.")
    show_help()

    while True:
        show_room(current_room)
        command = get_command()

        if command == "look":
            show_room(current_room)
        elif command == "help":
            show_help()
        elif command == "inventory":
            if inventory:
                print("Inventory: " + ", ".join(inventory))
            else:
                print("Your inventory is empty.")
        elif command == "quit":
            print("You leave the dungeon for another day.")
            break
        else:
            print("Unknown command. Type help to see your options.")


play()

What Does the Game Loop Manage?

  • play() keeps one game session together.
  • current_room starts at entrance.
  • inventory starts as an empty list.
  • The loop shows the current room before asking for the next command.
  • Save dungeon_game.py.
  • Run the new game loop from the integrated terminal:
python dungeon_game.py

What Should Change?

The game now prints the command guide plus the entrance description. It also shows the available exits before each prompt.

  • Enter inventory.
  • Enter quit.

You'll see Your inventory is empty. before the game displays the entrance again. The quit command still ends the loop.

Does the game close immediately?

  • Check that play() is aligned with the left edge of the file.
  • Check that the command branches sit inside while True:.
  • Confirm that the final play() call sits outside the function.
  • Help me debug why my play function does not keep running.

Collecting the key needs validation because the item belongs in one room. The same key should only appear once in the inventory.

  • Find the elif command == "quit": branch inside play().
  • Insert this key-handling branch directly above it:
        elif command == "take key":
            if current_room != "armory":
                print("There is no key here.")
            elif "key" in inventory:
                print("You already have the key.")
            else:
                inventory.append("key")
                print("You take the brass key.")

How Is Key Collection Validated?

  • The first condition rejects the command outside the armory.
  • The second condition prevents a duplicate key.
  • append() adds the key when both checks pass.
  • Save dungeon_game.py.
  • Test the location check by running the game:
python dungeon_game.py

What Does This Test Isolate?

The player still starts at the entrance. Trying to collect the key there tests the first condition without changing the inventory.

  • Enter take key.
  • Enter quit.

You'll see There is no key here. The loop continues until you quit.

Does taking the key cause an error?

  • Check that the entire branch lines up with the other elif branches.
  • Check that inventory.append("key") sits inside the final else block.
  • Help me fix the take key branch in my dungeon game.
Protect the gate and test the escape

Movement now needs to respect the exits listed for the current room. The gate adds one more condition because the player must carry the key before entering it.

  • Find the elif command == "quit": branch again.
  • Insert the navigation branch directly above it:
        elif command.startswith("go "):
            destination = command[3:].strip()
            if destination not in ROOMS[current_room]["exits"]:
                print("You cannot go there from here.")
            elif destination == "gate" and "key" not in inventory:
                print("The gate is locked. You need a key.")
            else:
                current_room = destination
                if current_room == "gate":
                    print("You unlock the gate and escape the Debug Dungeon!")
                    break

How Does Navigation Stay Safe?

  • startswith("go ") identifies movement commands.
  • destination stores the requested room name.
  • The first condition rejects destinations missing from the current room's exits.
  • The gate condition checks for the key before allowing the escape.
  • Save dungeon_game.py.

✔️ Awesome, I've got everything!

Your room map, helper functions, game state, command branches, and escape condition are now in place. Double check that you saved dungeon_game.py.

ⓧ I'd like to double check the full code

Compare your saved dungeon_game.py with this complete version.

ROOMS = {
    "entrance": {
        "description": "You stand at the dungeon entrance. The armory and gate are nearby.",
        "exits": ["armory", "gate"],
    },
    "armory": {
        "description": "Dusty weapons cover the walls. A brass key rests on a table.",
        "exits": ["entrance"],
    },
    "gate": {
        "description": "Moonlight shines through the bars of the exit gate.",
        "exits": ["entrance"],
    },
}


def get_command():
    return input("\n> ").strip().lower()


def show_room(room_name):
    room = ROOMS[room_name]
    print(f"\nLocation: {room_name}")
    print(room["description"])
    print("Exits: " + ", ".join(room["exits"]))


def show_help():
    print("Commands: look, go <room>, take key, inventory, help, quit")


def play():
    current_room = "entrance"
    inventory = []

    print("Escape the Debug Dungeon")
    print("Find the key and unlock the gate.")
    show_help()

    while True:
        show_room(current_room)
        command = get_command()

        if command == "look":
            show_room(current_room)
        elif command == "help":
            show_help()
        elif command == "inventory":
            if inventory:
                print("Inventory: " + ", ".join(inventory))
            else:
                print("Your inventory is empty.")
        elif command == "take key":
            if current_room != "armory":
                print("There is no key here.")
            elif "key" in inventory:
                print("You already have the key.")
            else:
                inventory.append("key")
                print("You take the brass key.")
        elif command.startswith("go "):
            destination = command[3:].strip()
            if destination not in ROOMS[current_room]["exits"]:
                print("You cannot go there from here.")
            elif destination == "gate" and "key" not in inventory:
                print("The gate is locked. You need a key.")
            else:
                current_room = destination
                if current_room == "gate":
                    print("You unlock the gate and escape the Debug Dungeon!")
                    break
        elif command == "quit":
            print("You leave the dungeon for another day.")
            break
        else:
            print("Unknown command. Type help to see your options.")


play()

What Should Match?

The file should contain the room map first. The four functions should follow in the same order shown here.

Before you run the game, consider whether the first gate attempt ends the loop.

  • Start the complete game by running this command:
python dungeon_game.py

What Does This Command Run?

The command executes the saved game from the open workspace. The final play() call starts a fresh session.

  • Enter go gate.
  • Enter go armory.
  • Enter take key.
  • Enter go entrance.
  • Enter inventory.
  • Enter go gate.

The first gate attempt prints The gate is locked. You need a key. The final attempt prints You unlock the gate and escape the Debug Dungeon! before the program ends.

That is the complete escape working. Your room data, inventory state, navigation checks, and victory condition now cooperate in one game loop.

For one last check, consider whether an impossible move changes the room or ends the game.

  • Start another game session by running the same command:
python dungeon_game.py

Why Start a Fresh Session?

Each call to play() creates a new entrance location plus an empty inventory. This gives the impossible move a clean test.

  • Enter go moon.
  • Enter quit.

You'll see You cannot go there from here. The entrance appears again because the invalid move does not end the loop.

Is movement behaving differently?

  • Check that destination comes from command[3:].strip().
  • Check that the exit validation runs before current_room = destination.
  • Check that the locked-gate condition tests for key in inventory.
  • Help me debug navigation or the locked gate in my dungeon game.

You built a complete command-line adventure from your own structure. The dungeon now handles exploration, item collection, invalid movement, quitting, and a visible victory.

Secret mission

Add a Countdown Lantern

Your escape route is complete, but the dungeon gives you unlimited time to find it. Add an eight-turn lantern that counts down with every command and ends the game when its light runs out.

Clean Up Your Resources

Clean Up Your Resources

Your dungeon project has no cloud resources or ongoing costs. Choose whether to keep the folder, close your current coding session, or delete the project.

Resources you used:

  • The local escape-debug-dungeon folder containing your saved dungeon_game.py game.

Keep everything running

No action needed. Choose this if you want to keep testing the game or extend it with more rooms.

  • Leave the escape-debug-dungeon folder in its current location.
  • Keep dungeon_game.py saved so your multi-room game and countdown lantern remain ready to run.

Pause - I'll come back to this later

This option ends your current coding session while preserving the complete game for another day.

  • Save dungeon_game.py.
  • Close Visual Studio Code.
  • Return to the escape-debug-dungeon folder in Visual Studio Code when you want another game session.

Delete - I don't want to use this again

Removing the folder permanently erases your dungeon code. Your Python and Visual Studio Code installations remain untouched.

  • Close Visual Studio Code.
  • Use Windows file search to locate the escape-debug-dungeon folder.
  • Open the folder's location from the matching search result.
  • Select the escape-debug-dungeon folder in File Explorer.
  • Press Shift+Delete to start permanent removal.
  • Confirm the permanent deletion when Windows asks.
  • Search Windows for escape-debug-dungeon again.

You should see no matching project folder. Your local game files are now removed.

Nice Work!

Nice Work!

You escaped the dungeon! You built a complete Python command-line adventure that responds to player choices.

Your game now handles navigation, inventory, invalid commands, victory, quitting, and a countdown loss condition.

You've learned how to:

  • Turn a written plan into a playable terminal adventure with normalized player commands.
  • Use a repeatable debugging process to replace a one-turn limitation with a resilient command loop.
  • Organize changing game state with functions, a room dictionary, and an inventory list.
  • Complete the Secret Mission by adding a countdown lantern that creates a turn limit and a second loss condition.

Ready to quiz yourself?