Text Adventure Game Tutorial: Teaching Parallel Arrays

This tutorial will guide you through creating a text adventure game in C++ using parallel arrays. This project is designed for first-year programming students to teach array manipulation, indexing, and game design concepts.

Note to Students: You are encouraged to use AI tools like Claude to help you understand concepts or debug your code. However, make sure you're implementing the code yourself to truly learn the concepts!

Understanding Parallel Arrays

Parallel arrays are multiple arrays where the same index in each array refers to the same entity. It's like having a table with rows and columns, but each column is stored in its own separate array.

Index Array1 Array2 Array3
0 Value1A Value1B Value1C
1 Value2A Value2B Value2C
2 Value3A Value3B Value3C

In Our Game Design:

Project Evolution Timeline

Iteration 1

"The Basics"

  • Room navigation
  • Player as "room 0"
  • Basic commands

Iteration 2

"The Collector"

  • Item interactions
  • Verb-noun commands
  • Multiple items per room

Iteration 3

"The Interactor"

  • Item interactions
  • State tracking
  • Special actions

Iteration 4

"The Container"

  • Containers
  • Items inside items
  • Puzzles

Iteration 5

"The Ultimate"

  • Locks and keys
  • Win conditions
  • Simple NPCs

Iteration 1: Basic Navigation

Core Implementation Details:

We'll start with parallel arrays for rooms and items:

Room Arrays:

// ROOM ARRAYS
vector<string> room_names = {
    "Player",          // Index 0 = Player (not a room)
    "Entrance Hall", 
    "Kitchen", 
    "Living Room", 
    "Secret Passage"
};

vector<string> room_descriptions = {
    "That's you!",     // Player description
    "A grand entrance with marble floors and a chandelier.",
    "A small kitchen with an old stove and sink.",
    "A cozy room with a fireplace and comfortable chairs.",
    "A narrow, dark passage hidden behind a bookshelf."
};

// Exits: N, E, S, W (-1 means no exit)
vector<vector<int>> room_exits = {
    {-1, -1, -1, -1},  // Player (not a location)
    {-1, 3, 2, -1},    // Entrance: No N, E to Living Room, S to Kitchen, No W
    {1, -1, -1, -1},   // Kitchen: N to Entrance, No other exits
    {-1, 4, -1, 1},    // Living Room: No N, E to Secret Passage, No S, W to Entrance
    {-1, -1, -1, 3}    // Secret Passage: No N, No E, No S, W to Living Room
};

Item Arrays:

// ITEM ARRAYS
vector<string> item_names = {
    "rusty key",
    "flashlight",
    "apple", 
    "knife",
    "old book",
    "letter"
};

// Location of each item (0=player, 1-4=rooms)
vector<int> item_locs = {
    1,  // rusty key in Entrance Hall
    1,  // flashlight in Entrance Hall
    2,  // apple in Kitchen
    2,  // knife in Kitchen
    3,  // old book in Living Room
    3   // letter in Living Room
};

Displaying Room and Items

// Display current room info
cout << "You are in the " << room_names[currentRoom] << endl;
cout << room_descriptions[currentRoom] << endl;

// Display items in this room
cout << "You see: ";
bool foundItems = false;
for (int i = 0; i < item_locs.size(); i++) {
    if (item_locs[i] == currentRoom) {
        if (foundItems) cout << ", ";
        cout << item_names[i];
        foundItems = true;
    }
}
if (!foundItems) cout << "nothing of interest";
cout << endl;

// Display inventory
cout << "Inventory: ";
bool hasItems = false;
for (int i = 0; i < item_locs.size(); i++) {
    if (item_locs[i] == 0) { // 0 = player inventory
        if (hasItems) cout << ", ";
        cout << item_names[i];
        hasItems = true;
    }
}
if (!hasItems) cout << "empty";
cout << endl;

Movement Commands

// Process movement commands
if (command == "north" || command == "n") {
    if (room_exits[currentRoom][0] != -1)
        currentRoom = room_exits[currentRoom][0];
    else
        cout << "You can't go that way." << endl;
}
else if (command == "east" || command == "e") {
    if (room_exits[currentRoom][1] != -1)
        currentRoom = room_exits[currentRoom][1];
    else
        cout << "You can't go that way." << endl;
}
Key Point: Notice how changing currentRoom to a new value effectively moves the player through the game world.

Iteration 2: Item Interactions

Adding Item Descriptions

// Add item descriptions
vector<string> item_descriptions = {
    "An old rusty key that might open something.",
    "A working flashlight with fresh batteries.",
    "A shiny red apple that looks delicious.",
    "A sharp kitchen knife.",
    "A dusty book with strange symbols on the cover.",
    "A sealed envelope with elegant handwriting."
};

Command Parsing

// Command parsing (add near the command input section)
string input, verb, noun;
cout << "> ";
getline(cin, input);           // Get the whole line
stringstream ss(input);        // Create a string stream
ss >> verb;                   // Extract first word as verb
ss >> noun;                   // Extract second word as noun

Take Command

if (verb == "take" && !noun.empty()) {
    bool found = false;
    for (int i = 0; i < item_names.size(); i++) {
        // If item matches name and is in current room
        if (item_names[i] == noun && item_locs[i] == currentRoom) {
            // Move to inventory (location 0)
            item_locs[i] = 0;
            cout << "You take the " << item_names[i] << "." << endl;
            found = true;
            break;
        }
    }
    if (!found) cout << "You don't see that here." << endl;
}

Drop Command

else if (verb == "drop" && !noun.empty()) {
    bool found = false;
    for (int i = 0; i < item_names.size(); i++) {
        // If item matches name and is in inventory
        if (item_names[i] == noun && item_locs[i] == 0) {
            // Move to current room
            item_locs[i] = currentRoom;
            cout << "You drop the " << item_names[i] << "." << endl;
            found = true;
            break;
        }
    }
    if (!found) cout << "You don't have that." << endl;
}

Examine Command

else if (verb == "examine" || verb == "look") {
    if (noun.empty()) {
        // Look at room again
        cout << room_descriptions[currentRoom] << endl;
    } else {
        // Look at specific item
        bool found = false;
        for (int i = 0; i < item_names.size(); i++) {
            // If item matches name and is in current room or inventory
            if (item_names[i] == noun && 
                (item_locs[i] == currentRoom || item_locs[i] == 0)) {
                cout << item_descriptions[i] << endl;
                found = true;
                break;
            }
        }
        if (!found) cout << "You don't see that here." << endl;
    }
}
Key Point: Notice how a single value change (item_locs[i] = 0) moves an item from a room to inventory. This demonstrates the power of parallel arrays!

Coding Challenges

Here are some challenges to help you extend your text adventure game:

Challenge 1: Room Map

Create a simple visual map of the rooms that displays when the player types "map".

Challenge 2: Item Weight

Add a new parallel array called item_weights and implement a weight limit for the player.

Challenge 3: Item Uses

Implement a "use [item]" command that performs special actions for certain items.

Challenge 4: Room State

Add a room_states array to track conditions like "light/dark" or "locked/unlocked".

AI Prompting Tips

Remember, you're encouraged to use AI tools like Claude to help you understand concepts. Here are some effective prompts:

Avoid asking the AI to "write the complete code for me" - instead, focus on understanding the concepts!

Full Source Code: Iteration 1

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main() {
    // ROOM ARRAYS
    vector<string> room_names = {
        "Player",          // Index 0 = Player (not a room)
        "Entrance Hall", 
        "Kitchen", 
        "Living Room", 
        "Secret Passage"
    };
    
    vector<string> room_descriptions = {
        "That's you!",     // Player description
        "A grand entrance with marble floors and a chandelier.",
        "A small kitchen with an old stove and sink.",
        "A cozy room with a fireplace and comfortable chairs.",
        "A narrow, dark passage hidden behind a bookshelf."
    };
    
    // Exits: N, E, S, W (-1 means no exit)
    vector<vector<int>> room_exits = {
        {-1, -1, -1, -1},  // Player (not a location)
        {-1, 3, 2, -1},    // Entrance: No N, E to Living Room, S to Kitchen, No W
        {1, -1, -1, -1},   // Kitchen: N to Entrance, No other exits
        {-1, 4, -1, 1},    // Living Room: No N, E to Secret Passage, No S, W to Entrance
        {-1, -1, -1, 3}    // Secret Passage: No N, No E, No S, W to Living Room
    };
    
    // ITEM ARRAYS
    vector<string> item_names = {
        "rusty key",
        "flashlight",
        "apple", 
        "knife",
        "old book",
        "letter"
    };
    
    // Location of each item (0=player, 1-4=rooms)
    // Initially distributed in different rooms
    vector<int> item_locs = {
        1,  // rusty key in Entrance Hall
        1,  // flashlight in Entrance Hall
        2,  // apple in Kitchen
        2,  // knife in Kitchen
        3,  // old book in Living Room
        3   // letter in Living Room
    };
    
    // Player starts in the entrance hall (room 1)
    int currentRoom = 1;
    
    // Game loop
    while (true) {
        cout << "\n----------------------------------------\n";
        
        // Display current room info
        cout << "You are in the " << room_names[currentRoom] << endl;
        cout << room_descriptions[currentRoom] << endl;
        
        // Display items in this room
        cout << "You see: ";
        bool foundItems = false;
        for (int i = 0; i < item_locs.size(); i++) {
            if (item_locs[i] == currentRoom) {
                if (foundItems) cout << ", ";
                cout << item_names[i];
                foundItems = true;
            }
        }
        if (!foundItems) cout << "nothing of interest";
        cout << endl;
        
        // Display inventory
        cout << "Inventory: ";
        bool hasItems = false;
        for (int i = 0; i < item_locs.size(); i++) {
            if (item_locs[i] == 0) { // 0 = player inventory
                if (hasItems) cout << ", ";
                cout << item_names[i];
                hasItems = true;
            }
        }
        if (!hasItems) cout << "empty";
        cout << endl;
        
        // Display available exits
        cout << "Exits: ";
        if (room_exits[currentRoom][0] != -1) cout << "North ";
        if (room_exits[currentRoom][1] != -1) cout << "East ";
        if (room_exits[currentRoom][2] != -1) cout << "South ";
        if (room_exits[currentRoom][3] != -1) cout << "West ";
        cout << endl;
        
        // Get player command
        string command;
        cout << "> ";
        cin >> command;
        
        // Process movement commands
        if (command == "north" || command == "n") {
            if (room_exits[currentRoom][0] != -1)
                currentRoom = room_exits[currentRoom][0];
            else
                cout << "You can't go that way." << endl;
        }
        else if (command == "east" || command == "e") {
            if (room_exits[currentRoom][1] != -1)
                currentRoom = room_exits[currentRoom][1];
            else
                cout << "You can't go that way." << endl;
        }
        else if (command == "south" || command == "s") {
            if (room_exits[currentRoom][2] != -1)
                currentRoom = room_exits[currentRoom][2];
            else
                cout << "You can't go that way." << endl;
        }
        else if (command == "west" || command == "w") {
            if (room_exits[currentRoom][3] != -1)
                currentRoom = room_exits[currentRoom][3];
            else
                cout << "You can't go that way." << endl;
        }
        else if (command == "quit") {
            break;
        }
        else {
            cout << "I don't understand that command." << endl;
        }
    }
    
    cout << "Thanks for playing!" << endl;
    return 0;
}

Resources

Have fun teaching parallel arrays through text adventures!