变量在某处被切换

Variables are getting switched up somewhere

我制作了一个随机迷宫生成器,它接受 3 个命令行参数(高度、宽度、种子值)。迷宫本身已经完成,大部分时间都在工作,但是我的参数宽度和高度在某处切换,我找不到它。例如如果我给参数 10 和 10,宽度应该是 10 * 5 + 1 = 51,高度应该是 10 * 3 + 1 = 31。我现在的高度是 51,宽度是 31。

有人 see/have 有任何提示可以调高这些变量吗?

#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 arguments 
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();
}

最明显的是您在 main 中创建的二维向量中交换了高度和宽度。纠正一下,来自

std::vector<std::vector<char>> Maze(Width * 5 + 1, std::vector<char>(Height * 3 + 1));

std::vector<std::vector<char>> Maze(Height * 3 + 1, std::vector<char>(Width * 5 + 1));

... 不会开箱即用,因为你已经将 HeightWidth 与幻数相乘,并且你在 Path 中犯了同样的错误你在哪里使用 Grid[xPos][yPos] 而不是 Grid[yPos][xPos]。更改两者可以纠正您询问的问题。

我们在学校被教导要思考 {x, y} 但由于您逐行打印并且 C++ 中的数组存储在 row-major order 中,我建议您在任何地方都使用 {y, x}在你的程序中。这样就不太可能出现这样的错误。

您还可以修复程序中的其他一些细节。

  • 你复制你的迷宫vector。通过引用传递它。
  • 不要在 main 中创建原始迷宫。让 Maze class 创建(并拥有它)。
  • Path - 如果甚至需要 class,应该在 Maze 拥有的迷宫中开辟路径,而不是从 Maze 复制迷宫。
  • carvePath 算法有时会“把自己画到一个角落里”而无法填满整个迷宫。我可能不会为此使用递归。
  • 每次调用 carvePath 时,您都会创建一个新的 伪随机数生成器 。我建议您只创建 one 并将其用于整个程序。
  • 用户提供的种子未被使用,因此您将使用相同的种子获得不同的迷宫。

此外,实际的向量会更简单 std::string:

std::vector<std::string>(Height, std::string(Width, '#'));

当你想打印迷宫时,你可以只打印 vector 中的每个 std::string

void Path::printMaze() {
    for(auto& row : Grid) std::cout << row << '\n';
}

每次都无法填满整个地图是因为Path::carvePath只尝试随机寻找一个有效方向4次。一种解决方法是将尝试次数增加到一个很大的数目,使得它不太可能找不到所有空闲点,但这有点浪费,而且仍然不会是 100%。没有不必要尝试的 100% 修复可能如下所示。请注意,我在此处已将其 {y, x} 无处不在:

#include <algorithm>  // std::shuffle
#include <array>      // std::array
#include <utility>    // std::pair

// Find a path using recursion
void Path::carvePath(int yPos, int xPos) {
    static std::mt19937 rng(std::random_device{}());

    Grid[yPos][xPos] = ' ';

    // all direction pairs
    std::array<std::pair<int, int>, 4> Directions{{
        {-1, 0},
        {+1, 0},
        {0, -1},
        {0, +1},
    }};

    // ... in random order
    std::shuffle(Directions.begin(), Directions.end(), rng);

    // ... and go through all 4 - it can now not miss a free spot
    for(auto [toY, toX] : Directions) { // structured binding + range-based for loop
        int y2 = yPos + toY * 2;
        int x2 = xPos + toX * 2;
        if(checkValid(y2, x2) && Grid[y2][x2] == '#') {
            Grid[yPos + toY][xPos + toX] = ' ';
            carvePath(y2, x2);
        }
    }
}

如果您不能使用 C++17 功能 structured bindings,您可以将上面的那部分循环替换为:

    for(const auto& dir : Directions) {
        int toY = dir.first;
        int toX = dir.second;
        ...