Skip to Content
Course content

282: Practice Exercise: Building a Simple Text-Based Adventure Game

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've reached a point in the course where you know how to use classes, maps, and loops, but the real test of a software engineer isn't knowing the syntax—it's knowing how to structure a system so it doesn't collapse under its own weight the moment you add a new feature. A text-based adventure game is the perfect playground for this. It seems simple on the surface, but it's a trap for those who rely too heavily on conditional logic.

The Hard-Coded Maze

When I first started building these kinds of projects, my instinct was to handle everything inside a giant while loop using a series of if and else if statements. I'd track the player's location with a string, like String currentRoom = "Hallway";, and then write logic like this:

if (currentRoom.equals("Hallway") && input.equals("north")) {
    currentRoom = "Kitchen";
    System.out.println("You entered the kitchen. It smells like old cabbage.");
} else if (currentRoom.equals("Kitchen") && input.equals("south")) {
    currentRoom = "Hallway";
    System.out.println("You're back in the hallway.");
}

At first, this feels productive. You're seeing results immediately. But here is where it breaks: the moment you want to add a tenth room, or a locked door that requires a key, or a monster that only appears if you've visited the library first. Your Main method becomes a thousand-line monster of nested conditionals. If you decide to rename "Hallway" to "Grand Corridor," you have to find and replace that string in twenty different places. It's brittle, it's hard to test, and it's a nightmare to maintain.

Turning Geography into Data

The professional way to handle this is to stop thinking of the game world as a series of "checks" and start thinking of it as a graph of objects. Instead of using strings to track location, we create a Room class. This class shouldn't just hold a description; it should hold its own exits. I usually use a HashMap<String, Room> for this, where the key is the direction (like "north") and the value is the actual Room object the player moves into.

public class Room {
    private String description;
    private Map<String, Room> exits = new HashMap<>();

    public Room(String description) {
        this.description = description;
    }

    public void setExit(String direction, Room neighbor) {
        exits.put(direction, neighbor);
    }

    public Room getExit(String direction) {
        return exits.get(direction);
    }
}

Now, look at how the movement logic changes. Your game loop no longer cares which room the player is in. It doesn't need to know if they are in the "Kitchen" or the "Dragon's Lair." It just asks the current room for the exit in the given direction:

Room nextRoom = currentRoom.getExit(input);
if (nextRoom == null) {
    System.out.println("You can't go that way!");
} else {
    currentRoom = nextRoom;
    System.out.println(currentRoom.getDescription());
}

The Cost of Abstraction

I'll be honest with you: this approach requires more "up-front" work. You have to define the classes, instantiate all your rooms, and manually link them together before the game even starts. To a beginner, this feels like unnecessary boilerplate. You're writing more code before the player can even take their first step.

But here is the trade-off: you've decoupled the engine (the code that handles movement and input) from the content (the layout of your world). If you want to add 100 more rooms, you don't have to write a single new if statement. You just create more Room objects and link them. This is the core of scalable software design: move the volatile parts of your program (the data) out of the stable parts (the logic).




📋 Practical Task

Exercise: Building a Haunted Mansion Navigator with Dynamic Room Transitions

Your task is to implement a text adventure engine based on the "Geography as Data" pattern described in the lesson. Avoid using if/else blocks to handle specific room names.

  • Create a Room class that contains a description and a Map<String, Room> for exits.
  • In your Main class, instantiate at least four rooms: Foyer, Library, Kitchen, and Cellar.
  • Link them together so that:
    • Foyer goes North to Library and East to Kitchen.
    • Library goes South to Foyer and Down to Cellar.
    • Kitchen goes West to Foyer.
    • Cellar goes Up to Library.
  • Implement a Scanner loop that accepts directions ("north", "south", "east", "west", "up", "down").
  • The program should print the current room's description and update the player's location dynamically using the Room object's exit map.
  • Ensure the game handles invalid directions gracefully without crashing.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.