0

I'm currently trying to make a program that will generate a maze to be exported to a game. This program will take user input to set some properties of the maze. I want one of the options to be if the maze will have only two dimensions (a single floor), or three (two or more floors). To achieve that, I'm dynamically allocating an array int the Maze class like so:

In Maze.hpp:

class Maze {
    private:
        unsigned int width_, length_, height_;

        Cell*** matrix = nullptr;
};

In Maze.cpp:

Maze::Maze() {           // Default constructor
    width_ = 20;
    length_ = 20;
    height_ = 0;

    matrix = new Cell**[width_];
    for (unsigned int x {}; x < width_; ++x) {
        matrix[x] = new Cell*[length_];
        for (unsigned int y {}; y < length_; ++y) {
            matrix[x][y] = new Cell(x, y);
        }
    }
}

Maze::Maze(int width, int length) {           // 2D maze constructor
    width_ = width;
    length_ = length;
    height_ = 0;

    matrix = new Cell**[width_];
    for (unsigned int x {}; x < width_; ++x) {
        matrix[x] = new Cell*[length_];
        for (unsigned int y {}; y < length_; ++y) {
            matrix[x][y] = new Cell(x, y);
        }
    }
}

Maze::Maze(int width, int length, int height) {    // 3D maze constructor
    width_ = width;
    length_ = length;
    height_ = height;

    matrix = new Cell**[width_];
    for (unsigned int x {}; x < width_; ++x) {
        matrix[x] = new Cell*[length_];
        for (unsigned int y {}; y < length_; ++y) {
            matrix[x][y] = new Cell[height];
            for (unsigned int z {}; z < height_; ++z) {
                matrix[x][y][z] = Cell(x, y, z);
            }
        }
    }
}

But as you can see, if I use two dimensions, I end up with a pointer for every individual cell in the maze, meanwhile, with three dimensions I end up with a cell object. I would prefer if in both cases I could have a cell object, but I don't know how to achieve that.

Is there a way to do this? Or is this the only option I have?

As asked, here is the declaration of Cell:

Cell.hpp:

class Cell {
    private:
        unsigned int xPos_, yPos_, zPos_;
    public:
        Cell(unsigned int xPos, unsigned int yPos);
        Cell(unsigned int xPos, unsigned int yPos, unsigned int zPos);
        Cell();
};

Cell.cpp:

Cell::Cell(unsigned int xPos, unsigned int yPos) {
    xPos_ = xPos;
    yPos_ = yPos;
}

Cell::Cell(unsigned int xPos, unsigned int yPos, unsigned int zPos) {
    xPos_ = xPos;
    yPos_ = yPos;
    zPos_ = zPos;
}
Spiwocoal
  • 27
  • 6
  • use `std::vector` or `std::array`. And isnt a 2D maze just a 3D maze with only one 2D entry? That would simplify the issue a bit – 463035818_is_not_an_ai Apr 12 '20 at 18:01
  • [See this](https://stackoverflow.com/questions/52068410/allocating-a-large-memory-block-in-c/52069368#52069368) if you must use triple pointers instead of the convenient `std::vector`. – PaulMcKenzie Apr 12 '20 at 18:02
  • 1
    According to your description, a 2D array would simply be a 3D array with only one value in the third dimension. You should always create a 3D array, but with only one value in the 3rd dimension axis. Oh, and you should open your C++ book to the chapter that explains how to use `std::vector`, read it, then get rid of all `new` and `delete` statements in the shown code. Their only use is a fertile breeding ground for bugs. – Sam Varshavchik Apr 12 '20 at 18:02
  • @SamVarshavchik I know how to use `std::vector`, but I remember being told to never use vectors for multidimensional arrays as that could generate a lot of problems. – Spiwocoal Apr 12 '20 at 18:06
  • @Spiwocoal -- Well, your implementation of the triple pointers is one of the worst way of doing this. The memory allocated is strewn all over the heap. Look at the solution I linked to, as that has less memory fragmentation. Three calls to `new[]` in total, not nested calls to `new[]` in loops. – PaulMcKenzie Apr 12 '20 at 18:09
  • 1
    Do you remember what those "lot of problems" were? There's nothing automatically wrong with using vectors for multi-dimensional arrays. There are certain situations where they'll be sub-optimal, but, in general, you cannot just take these sweeping generalizations for granted unless you understand precisely what's the underlying reason for them. – Sam Varshavchik Apr 12 '20 at 18:18
  • @SamVarshavchik If I recall correctly, it had to do with the fact that the vectors could be of different size, but now that I think about it, in my case it would be difficult to have a different sized vector, if I managed to get one, it would be because of some programming error. – Spiwocoal Apr 12 '20 at 18:40
  • Vectors can contain vectors of different sizes without any issues. Either your recollection is incorrect, or whoever told you that doesn't really know C++ very well, and you should not listen to them, any more. – Sam Varshavchik Apr 12 '20 at 19:06

1 Answers1

0

As suggested in the comments of the question, I'll change to std::vector instead of using triple pointers.

Also, as a 2D array is simply a 3D array with only one value in the third dimension, I will just change the code to that. (This was also suggested in the comments)

I'll update this answer with the new code when I'm done with it.

UPDATE:

Here's what the final code looks like:

Cell.hpp:

class Cell {
    private:
        unsigned xPos_, yPos_, zPos_;
    public:
        Cell(unsigned xPos, unsigned yPos, unsigned zPos);
        Cell();
};

Cell.cpp:

Cell::Cell(unsigned xPos, unsigned yPos, unsigned zPos) {
    xPos_ = xPos;
    yPos_ = yPos;
    zPos_ = zPos;
}

Maze.hpp:

class Maze {
    private:
        unsigned width_, length_, height_;

        std::vector<std::vector<std::vector<Cell>>> matrix;

        void generateMatrix();
    public:
        Maze();
        Maze(unsigned width, unsigned length);
        Maze(unsigned width, unsigned length, unsigned height);
};

Maze.cpp:

Maze::Maze() {                                      // Default constructor
    width_ = 20;
    length_ = 20;
    height_ = 1;

    Maze::generateMatrix();
}

Maze::Maze(unsigned width, unsigned length) {                 // 2D maze constructor
    width_ = width;
    length_ = length;
    height_ = 1;

    Maze::generateMatrix();
}

Maze::Maze(unsigned width, unsigned length, unsigned height) {    // 3D maze constructor
    width_ = width;
    length_ = length;
    height_ = height;

    Maze::generateMatrix();
}

void Maze::generateMatrix() {
    for (unsigned x {}; x < width_; ++x) {
        matrix.push_back(std::vector<std::vector<Cell>>());

        for (unsigned y {}; y < length_; ++y) {
            matrix.at(x).push_back(std::vector<Cell>());

            for (unsigned z {}; z < height_; ++z) {
                matrix.at(x).at(y).push_back(Cell(x,y,z));
            }
        }
    }
}
Spiwocoal
  • 27
  • 6