变量在某处被切换
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));
... 不会开箱即用,因为你已经将 Height
和 Width
与幻数相乘,并且你在 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;
...
我制作了一个随机迷宫生成器,它接受 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));
... 不会开箱即用,因为你已经将 Height
和 Width
与幻数相乘,并且你在 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;
...