I have made a random maze generator which takes in 3 commandline arguements (Height, Width, SeedValue). The maze in itself is finished, it works most of the time, however my parameters width and height are getting switched somewhere and I cant find it. e.g. if I give the parameters 10 and 10 the width should be 10 * 5 1 = 51 and the Height should be 10 * 3 1 = 31. I now have a height of 51 and a width of 31.
Does anyone see/have any tips where these variables might get switched up?
#include <iostream>
#include <vector>
#include <stack>
#include <sstream>
#include <time.h>
#include <random>
#define North 1
#define East 2
#define South 3
#define West 4
class Maze {
private:
int mazeHeight;
int mazeWidth;
int seedValue;
std::vector <std::vector <char>> Maze_maze;
public:
void checkuserInput(int Input1, int Input2);
void mazeConstructor(int x, int y, int z, std::vector <std::vector <char>> vect);
std::vector <std::vector <char>> initializeMaze();
};
//Make the variables accesible
void Maze::mazeConstructor(int x, int y, int z, std::vector <std::vector <char>> vect) {
mazeWidth = x;
mazeHeight = y;
seedValue = z;
Maze_maze = vect;
}
// Initialize the walls with '#'
std::vector <std::vector <char>> Maze::initializeMaze() {
for (unsigned int i = 0; i < Maze_maze.size(); i ) {
for (unsigned int j = 0; j < Maze_maze[0].size(); j ) {
Maze_maze[i][j] = '#';
}
}
return Maze_maze;
}
class Path {
private:
std::vector <std::vector <char>> Grid;
int Height;
int Width;
int toX = 0;
int toY = 0;
public:
void pathConstructor(std::vector <std::vector <char>> Maze, int mazeWidth, int mazeHeight);
bool checkValid(int xPos, int yPos);
void carvePath(int xPos, int yPos);
void printMaze();
};
// Make the variables accessible
void Path::pathConstructor(std::vector <std::vector <char>> Maze, int mazeWidth, int mazeHeight) {
Grid = Maze;
Height = mazeHeight;
Width = mazeWidth;
}
bool Path::checkValid(int xPos, int yPos) {
if(xPos < 0 || xPos >= Width - 1) {
return false;
}
if( yPos < 0 || yPos >= Height) {
return false;
}
return true;
}
// Find a path using recursion
void Path::carvePath(int xPos, int yPos) {
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> randomNumber(0, 3);
Grid[xPos][yPos] = ' ';
std::vector <int> Directions (4);
Directions[0] = North;
Directions[1] = East;
Directions[2] = South;
Directions[3] = West;
for (int i = 0; i < 4; i) {
int toX = 0;
int toY = 0;
switch (Directions[randomNumber(rng)]) {
case North:
toY = -1;
break;
case South:
toY = 1;
break;
case East:
toX = 1;
break;
case West:
toX = -1;
break;
}
int x2 = xPos (toX << 1);
int y2 = yPos (toY << 1);
if (checkValid(x2, y2)) {
if (Grid[x2][y2] == '#') {
Grid[x2 - toX][y2 - toY] = ' ';
carvePath(x2, y2);
}
}
}
}
// Output the maze
void Path::printMaze() {
for (unsigned int i = 0; i < Grid.size(); i ) {
for (unsigned int j = 0; j < Grid[0].size(); j ) {
std::cout << Grid[i][j];
}
std::cout << std::endl;
}
}
// Check if user input is valid
void checkUserInput(int Input1, int Input2) {
int checkIntWidth = 0;
int checkIntHeight = 0;
if (!(Input1 >> checkIntWidth) || !(Input2 >> checkIntHeight)) {
throw std::runtime_error ("Invalid input");
}
}
// Get command line arguements
int main(int argc, char* argv[]) {
Maze c1;
Path c2;
srand (time(0));
int Height;
int Width;
int seedValue;
Height = atoi(argv[1]);
Width = atoi(argv[2]);
try {
checkUserInput(Width, Height);
}
catch(std::runtime_error& e) {
std::cerr << e.what() << std::endl;
return 1;
}
if (argc > 3) {
seedValue = atoi(argv[3]);
} else {
seedValue = rand();
}
std::vector <std::vector <char>> Maze (Width * 5 1, std::vector <char> (Height * 3 1));
c1.mazeConstructor(Width, Height, seedValue, Maze);
c2.pathConstructor(c1.initializeMaze(), Width * 5 1, Height * 3 1);
c2.carvePath(1, 1);
c2.printMaze();
}
CodePudding user response:
The most obvious thing is that you've swapped height and width in the 2d vector you create in main. Just correcting it, from
std::vector<std::vector<char>> Maze(Width * 5 1, std::vector<char>(Height * 3 1));
to
std::vector<std::vector<char>> Maze(Height * 3 1, std::vector<char>(Width * 5 1));
... will not work right out of the box though since you've multiplied Height and Width with magic numbers and you've made the same mistake in Path where you use Grid[xPos][yPos] instead of Grid[yPos][xPos]. Changing both corrects the problem you are asking about.
We're taught in school to think {x, y} but since you print row by row and that arrays in C is stored in row-major order, I suggest that you use {y, x} everywhere in your program. That makes mistakes like this less likely.
You have some other details in the program that you could fix too.
- You copy your maze
vectoraround. Pass it by reference. - Don't create the original maze in
main. Let theMazeclass create (and own it). Path- if that class is even needed, should probably carve paths in the maze that is owned byMaze, not copy a maze fromMaze.- The
carvePathalgorithm sometimes "paints itself into a corner" and fails to fill the whole maze. I would probably not use recursion for this. - Each time
carvePathis called you create a new pseudo random number generator. I suggest that you only create one and use that for the whole program. - The seed the user gives is not used so you'll get different mazes with the same seed.
Also, the actual vector would be simpler with a std::string:
std::vector<std::string>(Height, std::string(Width, '#'));
You could that just print each std::string in the vector when you want to print the maze.
void Path::printMaze() {
for(auto& row : Grid) std::cout << row << '\n';
}
