Text adventure rooms - Voids or Classes?

Hi, I'm working on a little text adventure project in C++ and I'm not quite sure how I'll do the rooms in the game. I was considering using a room class and making a 2D array of rooms with values for paths away from the rooms (North, East, West, South) and NPCs or Items in the room being portrayed by arrays as well. But I'm not totally sure about this approach and am considering using methods instead. It would be great to get some insight and help on this project (especially in terms of making the code less messy).

Thanks in advance.
Ticbow (1)
Hi, I'm working on a little text adventure project in C++ and I'm not quite sure how I'll do the rooms in the game. I was considering using a room class and making a 2D array of rooms with values for paths away from the rooms (North, East, West, South) and NPCs or Items in the room being portrayed by arrays as well. But I'm not totally sure about this approach and am considering using methods instead. It would be great to get some insight and help on this project (especially in terms of making the code less messy).

Thanks in advance.


classes sound better. Then you can have a graph structure instead of a giant 2d mess -- basically a tree where each room has up to 4 children, and the nodes would be doubly linked so you can go backwards. The biggest advantage I see is that right away re-arranging the map is less painful in tree form than as an array, where you have to move everything around, vs the tree, where you just relink the rooms that are affected (though this may spawn a big ripple effect!). Even if you do a 2d array of some sort, you can have an array of rooms or 2d array of rooms.
The advantage of a 2d array is that you have a map you can visualize. Its probably not worth it; you can write a visualizer real fast.

I say all this with little idea of your design though. Maybe you should tell us more if this does not sound right..
Last edited on
A class for a Room seems like a good place to start.

But you might want to avoid just a 2D array of rooms unless you have a very rigid and flat geometry, and all the rooms are the same size.

For example, you couldn't have stairs which lead to rooms on top of other rooms.
A long hall or corridor would have to be traversed as "you're in the hall", "you're in the hall", you're in the hall", "there is a door".


> NPCs or Items in the room being portrayed by arrays as well.
I'd suggest you make these lists.
Lists are a lot easier to manage when say you pick an item up, or an NPC leaves the room.
Don't use a 2D array of rooms. Instead, use a "graph" of connections between the rooms.
Read the map in from a text file. First draw out the map and number the rooms from 1 to the number of rooms. In the text file, the connections to other rooms are represented by a list of 6 numbers for directions in the order: north east south west down up. A zero means no connection in that direction, otherwise its the room number for that direction.

Example map:

            (1)Kitchen -- (2)Pantry   (3)Bedroom

                 |                        |
                 |                        |

(7)Room7 -- (4)Dining -------------- (5)Hallway ---- (8)Room8
               Room                          
                 |                        |    \ down
                 |                        |     \ up

             (9)Room9                (10)Room10   (6)Dungeon

Corresponding text file. Note that a blank line separates rooms since the descriptions can have more than one line.

1
Kitchen
0 2 4 0 0 0
You are in a large messy kitchen.
Pots and pans are strewn about.

2
Pantry
0 0 0 1 0 0
You are in the pantry.
There are shelves containing dry goods.

3
Bedroom
0 0 5 0 0 0
You are in a bedroom.
The bed has not been made.

4
Dining Room
1 5 9 7 0 0
You are in a dining room.
Food is still on the table.

5
Hallway
3 8 10 4 6 0
You are in a hallway with many exits.

6
Dungeon
0 0 0 0 0 5
You are in a creepy dungeon.
There is a skeleton next to one wall.

7
Room Seven
0 4 0 0 0 0
You are in room seven.

8
Room Eight
0 0 0 5 0 0
You are in room eight.

9
Room Nine
4 0 0 0 0 0
You are in Room nine.

10
Room Ten
5 0 0 0 0 0
You are in room ten.

Some quickly hacked together code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <cctype>

using std::cout, std::cin, std::string, std::vector;

enum { North, East, South, West, Down, Up, NumDirs };

struct Room
{
    string name;
    string descrip;
    int dirs[NumDirs];

    Room(const string& nm, const string& desc, const int* d)
        : name(nm), descrip(desc)
    {
        for (int i = 0; i < NumDirs; ++i) dirs[i] = d[i];
    }
};

auto readRooms(const string& filename)
{
    vector<Room> rooms;
    string line;
    std::ifstream in(filename);
    if (!in)
    {
        std::cerr << "Error: Cannot open input file " << filename << '\n';
        std::exit(EXIT_FAILURE);
    }
    using std::getline;
    for (int n = 1, num; in >> num; ++n)
    {
        if (n != num)
        {
            std::cerr << "Error: rooms are out of order: "
                      << num << " should be " << n << ".\n";
            exit(EXIT_FAILURE);
        }
        string name, descrip;
        getline(in >> std::ws, name);
        int d[NumDirs];
        for (int i = 0; i < NumDirs; ++i) in >> d[i];
        getline(in >> std::ws, descrip);
        while (getline(in, line) && !line.empty())
            descrip += "\n" + line;
        rooms.emplace_back(name, descrip, d);
    }
    return rooms;
}

int charDirToNumDir(char cd)
{
    switch (cd)
    {
    case 'n': return 0;
    case 'e': return 1;
    case 's': return 2;
    case 'w': return 3;
    case 'd': return 4;
    case 'u': return 5;
    }
    return -1;
}

std::string numDirToString(int d)
{
    static const char* sdirs[NumDirs]
        {"North", "East", "South", "West", "Down", "Up"};
    return sdirs[d];
}

void describeRoom(const Room& r)
{
    cout << r.name << '\n'
         << r.descrip << '\n'
         << "Exits are: ";
    for (int i = 0; i < NumDirs; ++i)
        if (r.dirs[i] != 0)
            cout << numDirToString(i) << ' ';
    cout << '\n';
}

void dumpRooms(const vector<Room>& rooms)
{
    for (const auto& r: rooms)
    {
        describeRoom(r);
        cout << '\n';
    }
}

void explore(const vector<Room>& rooms)
{
    int r = 0;
    while (true)
    {
        describeRoom(rooms[r]);
        int d = -1;
        while (true)
        {
            cout << "Direction: ";
            char cd;
            cin >> cd;
            cd = std::tolower(cd);
            if (cd == 'q') return;
            d = charDirToNumDir(cd);
            if (d != -1 && rooms[r].dirs[d] != 0) break;
            cout << "Bad direction\n";
        }
        r = rooms[r].dirs[d] - 1;
        cout << '\n';
    }
}

int main()
{
    auto rooms = readRooms("rooms.txt");
    //dumpRooms(rooms);
    explore(rooms);
}

Last edited on
1
2
//vector<Room*> rooms;
vector<Room> rooms;


> r = rooms[r]->dirs[d] - 1;
be careful with that
Last edited on
@ne555, agreed. I can't remember how I ended up with pointers. I've changed the post above.

be careful with that

Not sure what you mean with this.
The room numbers are 1-based so I'm converting them to 0-based for the vector.
Last edited on
Wow! I didn't expect this many responses! This was all really helpful, thank you! I'm going to try some of the ways that have been mentioned and will get back to you with what I go with. Thanks again!
Topic archived. No new replies allowed.