-1

I'm creating a text adventure with room names, descriptions and spaces for hints and items.

This is part of the solution so far, a simple struct with four string entries. A requirement is to keep the rooms initialisation data readable and editable as the 4x4 array works as a grid for my game world.

using namespace std;
#include <string>
struct Room
{
    string name;
    string description;
    string itemHint;
    string item;
};
Room rooms[4][4]= {
{{"...", "...", "...", "..."},
{"...", "...", "...", "..."},
{"...", "...", "...", "..."},
{"...", "...", "...", "..."}}, // rooms[0..3][0] data

{{"...", "...", "...", "..."}, // and so on

Now this works to some extent. But, when printing the rooms map of the game world I'm getting duplicate entries. The code is duplicating the room data four times per row [0..0][0..3].

void PrintMap()
{
    cout << endl;
    for (int v = 0; v < 4; v += 1)
    {
        for (int h = 0; h < 4; h += 1)
        {
            if (currentRoom.h == h && currentRoom.v == v)
                cout << "@";
            else
                cout << " ";
            cout << rooms[h, v]->name;
            string charstring = rooms[h, v]->name;
            int chars = charstring.length();
            int endSpaces = 24 - 1 - chars;
            for (int charSpaces = 1; charSpaces < endSpaces + 1; charSpaces += 1)
                cout << " ";
        }
        cout << endl << endl << endl;
    }
}

Here is a screenshot of the console application printed room map to help better explain this:

room map

I'm almost understanding why this occurs, but perhaps someone could explain it and has a valid solution. Of course as I've said I'd like to keep the code format for the rooms data readable, I gladly accept any code design additions.

Community
  • 1
  • 1

1 Answers1

1

You may be initializing data incorrectly due to confusion on your matrix. You need to view it as a table where the first dimension is the row and the second dimension is the column of the room.

Since you're initializing a struct c++ is able to do a type of initialization with the following syntax

Room room = {"A Room name", "A room description", "A hint", "An item"};

As documented here

When initializing a struct, the first initializer in the list initializes the first declared member (unless a designator is specified) (since C99), and all subsequent initializers without designators (since C99)initialize the struct members declared after the one initialized by the previous expression.

Now with that type of initialization in mind consider the following

   Room rooms[4][4] = {
            {

                    {"...", "...", "...", "..."}, // room col 0 at row 0 [0][0]
                    {"...", "...", "...", "..."}, // room col 1 at row 0 [0][1]
                    {"...", "...", "...", "..."}, // room col 2 at row 0 [0][2]
                    {"...", "...", "...", "..."}  // room col 3 at row 0 [0][3]
            },

            {
                    {"...", "...", "...", "..."}, // room col 0 at row 1 [1][0]
                    {"...", "...", "...", "..."}, // room col 1 at row 1 [1][1]
                    {"...", "...", "...", "..."}, // room col 2 at row 1 [1][2]
                    {"...", "...", "...", "..."}, // room col 3 at row 1 [1][3]
            }
    };

Inspecting the rooms as expected should work just fine

    // Print all data in the matrix.
    for (int rowIndex = 0; rowIndex < 4; rowIndex++) {
        cout << "--- Room info at row " << rowIndex << endl;
        for (int colIndex = 0; colIndex < 4; colIndex++) {
            cout << "Room name at point " << rowIndex << "," << colIndex << ":" << rooms[rowIndex][colIndex].name << endl;
        }
    }

I recommend reading up more on the link provided regarding structs. Hopefully this solves your confusion.

Edit:

After seeing your PrintMap method I noticed you're using the Arrow operator -> incorrectly in the context of what you're trying to achieve.

The way you're trying to access a specific row/col within your matrix is not a native way of doing so. In this case rooms[h, v]->name is equivalent to rooms[v]->name. What you're doing here is dereferencing the pointer on the left-hand side and accessing the value of the specified member of the struct on the right-hand side of the operator at the head of row x.

The following produces the same output where v is the row within the matrix.

string val = (*rooms[v]).name;
val = rooms[v]->name

Arrays are just pointers that point to the address of the first element and then the compiler reserves an amount of contiguous addresses based on the width of the array specified. Because of this, your code will execute fine, in theory, but will give you the undesirable outcome.

With that in mind, this is why you're essentially seeing duplicates as well since you're under the impression that the array get operator is getting both the row and column of each iteration respectively however it is merely getting the value of row v respectively in your case.

Your best option is to just use the dot . operator when iterating over your matrix to lessen confusion and give you your desired output.

Reading more on the arrow vs dot operators may help as well. I hope this information is of use to you. There is a useful discussion here regarding the two.

heaven
  • 23
  • 7
  • Thanks for the full description. I've adhered to the initialisation rule for a struct in my data list, I've triple checked that - despite incomplete code in my first example. Perhaps my problem is in `void PrintMap()` the use of `rooms[rowIndex][colIndex]->name` instead of `rooms[rowIndex][colIndex].name` because I cannot access the rooms data. The compiler warnings with the correction: `Error C2228 left of 'name' must have class/struct/union` – Square Mezzmer May 21 '20 at 18:17
  • @SquareMezzmer I've updated my post. Let me know if that clears up some concerns. – heaven May 21 '20 at 19:50
  • Thanks for a thorough answer. That clarifies what was happening and explains the problem. However I'm still not sure why I cannot access my rooms data with the dot operator. Is there a way I can refer to the array? As I stated, in the code the compiler errors wherever I refer to it `expression must have class type` – Square Mezzmer May 21 '20 at 20:09
  • @SquareMezzmer You can do something along the lines of `(rooms[v] + h)->name` in your nested loop where `h` is the column offset from the start of each row. This would be the equivalent of `rooms[v][h].name`. Hope all of this has been of some help. – heaven May 21 '20 at 20:50
  • Thanks, will keep trying! – Square Mezzmer May 21 '20 at 21:00
  • Yes, that is definitely a solution, you hit the nail on the head and I didn't have to change any code design. Thanks @ven! – Square Mezzmer May 22 '20 at 17:56
  • @SquareMezzmer No problem! – heaven May 23 '20 at 03:51