我想使用递归回溯在C ++中实现Maze生成算法。
我的代码完全正常工作,有点......我总是得到一个具有相同模式的输出。
迷宫尺寸2输出:
XXXXXX
X X
X XX X
X XX X
X X
XXXXXX
迷宫尺寸4输出:
XXXXXXXXXXXX
X X
X XX XX XX X
X XX XX XX X
X X
X XX XX XX X
X XX XX XX X
X X
X XX XX XX X
X XX XX XX X
X X
XXXXXXXXXXXX
我认为这是因为我在递归函数(genereerDoolhof())中使用了for循环,它以某种方式生成了多个路径;但这似乎不是问题所在。
比我想象的那样,因为算法在到达起始位置时没有停止,但这也不是问题。
我宁愿期待一个输出,其中迷宫从A点开始,到A点结束。它看起来更随机,而不是那么模式。
我的代码:
#include <iostream>
#include <vector>
#include <algorithm> //for shuffle
#include <cstdlib> //for rand()
#include <time.h> //for time
#include <iomanip> //for hex
using namespace std;
struct Positie{
int rij; int kolom;
};
struct Cel{
bool muurLinks, muurRechts, muurBoven, muurOnder;
bool bezocht;
};
typedef vector<vector<Cel>> Doolhof;
//Code voor weergave doolhof, bijvoorbeeld gebruike cout << doolhof
//Elke cell wordt weergegevendoor 3 X 3 keer ofwel X ofwel _
ostream& operator<<(ostream& stream, const Doolhof& doolhof){
//Print per doolhof rij, drie rijen tekstueel
for(auto row: doolhof){
for(const Cel& Cel: row){
if(!Cel.muurBoven)
stream << "X X";
else
stream << "XXX";
}
stream << endl;
for(const Cel& Cel: row){
if(!Cel.muurLinks && !Cel.muurRechts)
stream << " ";
else if(!Cel.muurLinks)
stream << " X";
else if(!Cel.muurRechts)
stream << "X ";
else if(!Cel.muurOnder || !Cel.muurBoven) //important: if left/right is closed, but top or down isnt'
stream << "X X";
else
stream << "XXX";
}
stream << endl;
for(const Cel& Cel: row){
if(!Cel.muurOnder)
stream << "X X";
else
stream << "XXX";
}
stream << endl;
}
stream << endl;
return stream;
}
//My Functions (definition)
Doolhof maakDoolhof(int dimensie);
Cel& getCel(Doolhof& doolhof, Positie positie);
vector<Positie> getGeldigeBuren(Doolhof& doolhof, Positie positie);
void murenWegTussenBuren(Doolhof& doolhof, Positie cel1, Positie cel2);
void genereerDoolhof(Doolhof& doolhof, Positie pos, bool debug);
//MAIN:
int main() {
//Dimension of doolhof
int n = 4;
//Variable for Doolhof
Doolhof doolhof;
doolhof = maakDoolhof(n);
//Set last parameter to 'true' for seeing all steps
genereerDoolhof(doolhof, {0,0}, false);
cout << doolhof;
return 0;
}
//My Functions (declaration)
//
//Creates the bases of a doolhof (no cells connected yet)
//param dimensie: Int -> Dimension of the doolhof
//return: type=Doolhof -> Returning the whole Doolhof
//Signature: Int -> Doolhof
Doolhof maakDoolhof(int dimensie) {
//Vector for Doolhof
Doolhof doolhof;
for (int i = 0; i < dimensie; i++) {
//Vector to hold all the cels making one row
vector<Cel> row;
for (int j = 0; j < dimensie; j++) {
//Creating a Cel and it's properties
Cel cel;
cel.muurLinks = true;
cel.muurRechts = true;
cel.muurBoven = true;
cel.muurOnder = true;
cel.bezocht = false;
//Adding cel to row
row.push_back(cel);
}
//Adding row to whole doolhof
doolhof.push_back(row);
}
//Returning doolhof
return doolhof;
}
//Returns Cell at specified position
//param doolhof: Doolhof& -> Reference to the Doolhof vector
//param positie: Positie -> Position of Cell to return
//return: type=Cel& -> Reference to the cell at specified position
Cel& getCel(Doolhof& doolhof, Positie positie) {
//Parameters to local variables
int row = positie.rij;
int col = positie.kolom;
return doolhof[row][col];
/*
WRONG
This is for 1 dimensional vector...
//Getting dimension by taking length of first row :P
int dimension = doolhof[0].size();
//Formula to get index of cell in the Doolhof-vector
//(row - 1) * dimensionOfDoolhof + col
int indexOfCell = (row - 1) * dimension + col;
//Returning element on indexOfCell
return doolhof[indexOfCell]
*/
}
//Returns all the valid cells around the specified position
//Cells laying out of the maze ain't valid for example
//param doolhof: Doolhof& -> Reference to the Doolhof vector
//param positie: Positie -> Positie of the cell to check
//return: type=vector<Positie> -> Vector containing all valid positions
vector<Positie> getGeldigeBuren(Doolhof& doolhof, Positie positie) {
//Vector holding valid positions of cells
vector<Positie> valid;
//Dimension
int dimension = doolhof[0].size();
//Position to add
Positie pos;
//Checking for horizontal cells
//Check if left is valid
if (positie.kolom - 1 >= 0 &&
positie.kolom < dimension &&
positie.rij < dimension &&
positie.rij >= 0) {
pos.rij = positie.rij;
pos.kolom = positie.kolom -1;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
//Check if right is valid
if (positie.kolom + 1 < dimension &&
positie.kolom >= 0 &&
positie.rij < dimension &&
positie.rij >= 0) {
pos.rij = positie.rij;
pos.kolom = positie.kolom +1;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
//Checking for vertical cells
//Check if upper is valid
if (positie.rij - 1 >= 0 &&
positie.rij < dimension &&
positie.kolom < dimension &&
positie.kolom >= 0) {
pos.rij = positie.rij -1;
pos.kolom = positie.kolom;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
//Check if bottom is valid
if (positie.rij + 1 < dimension &&
positie.rij >= 0 &&
positie.kolom < dimension &&
positie.kolom >= 0) {
pos.rij = positie.rij +1;
pos.kolom = positie.kolom;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
return valid;
}
//Takes away walls between specific cells
//param doolhof: Doolhof& -> Reference to the doolhof-vector
//param cel1: Positie -> Position of the first cell
//param cel2: Positie -> Position of the second cell
//return: void
void murenWegTussenBuren(Doolhof& doolhof, Positie cel1, Positie cel2) {
//Variable for cells we're talking about
Cel cel_a = getCel(doolhof, cel1);
Cel cel_b = getCel(doolhof, cel2);
//Case 1: HORIZONTAL -> cel2 <> cel1
if (cel1.rij == cel2.rij &&
cel1.kolom == cel2.kolom +1) {
cel_a.muurLinks = false;
cel_b.muurRechts = false;
}
//Case 2: HORIZONTAL -> cel2 <> cel1
else if (cel2.rij == cel1.rij &&
cel2.kolom == cel1.kolom +1) {
cel_a.muurRechts = false;
cel_b.muurLinks = false;
}
//Case 3: VERTICAL -> cel1 ^ cel2
else if (cel1.rij == cel2.rij +1 &&
cel1.kolom == cel2.kolom) {
cel_a.muurBoven = false;
cel_b.muurOnder = false;
}
//Case 4: VERTICAL -> cel2 ^ cel1
else if (cel1.rij +1 == cel2.rij &&
cel1.kolom == cel2.kolom) {
cel_a.muurOnder = false;
cel_b.muurBoven = false;
}
//Case x: ERROR, just return
else return;
//Setting the cell-values back in doolhof
getCel(doolhof, cel1) = cel_a;
getCel(doolhof, cel2) = cel_b;
return;
}
//Generates the final doolhof (takes away walls & connects cells,...)
//param doolhof: Doolhof& -> Reference to the doolhof
//param positie: Positie -> Position to do recursion on
//param debug: Bool -> Prints iteration-steps when true
//return: void
void genereerDoolhof(Doolhof& doolhof, Positie pos, bool debug) {
//Get cell from position
Cel cell = getCel(doolhof, pos);
//Cel = visited
getCel(doolhof, pos).bezocht = true;
//Get valid neighbours
vector<Positie> valid;
valid = getGeldigeBuren(doolhof, pos);
//If no valid neighbours
if (valid.size() == 0) return;
Positie validPos;
for (int i = 0; i < valid.size(); i++) {
validPos = valid[i];
murenWegTussenBuren(doolhof, pos, validPos);
genereerDoolhof(doolhof, validPos, false);
}
//Printing out all iteration steps when debug == true
if (debug) cout << doolhof;
}
这是一个非常大的代码;但我用评论记录了一切。 我很确定问题出现在最后一个函数(genereerDoolhof)中,这是递归回溯函数;但是我当然不确定。
因为我的代码包含一些荷兰语,所以我也会在这里解释所有的功能。
所有功能的简短说明:
ostream& operator<<(ostream& stream, const Doolhof& doolhof)
忽略这一点,这只是为了能够cout << doolhof;
Doolhof 意味着'迷宫'开始
Doolhof maakDoolhof()只需将所有单元格放入迷宫中,并使用单元格默认值(所有墙都为真并设置,并由 递归是错误的)
我认为我非常接近实施迷宫算法,我只需要最后一点逻辑并帮助完全解决它。我非常感谢你的帮助!
函数genereerDoolhof(..,..,true)包含'debug-mode',将最后一个参数设置为true以查看所有步骤和迭代。
修改 我编辑了我的代码,现在的问题是我在运行时收到错误'Segmentation fault';
代码:
#include <iostream>
#include <vector>
#include <algorithm> //for shuffle
#include <cstdlib> //for rand()
#include <time.h> //for time
#include <iomanip> //for hex
#include <stack>
using namespace std;
struct Positie{
int rij; int kolom;
};
struct Cel{
bool muurLinks, muurRechts, muurBoven, muurOnder;
bool bezocht;
};
//Stack holding positions
std::stack<Positie> myStack;
typedef vector<vector<Cel>> Doolhof;
//Code voor weergave doolhof, bijvoorbeeld gebruike cout << doolhof
//Elke cell wordt weergegevendoor 3 X 3 keer ofwel X ofwel _
ostream& operator<<(ostream& stream, const Doolhof& doolhof){
//Print per doolhof rij, drie rijen tekstueel
for(auto row: doolhof){
for(const Cel& Cel: row){
if(!Cel.muurBoven)
stream << "X X";
else
stream << "XXX";
}
stream << endl;
for(const Cel& Cel: row){
if(!Cel.muurLinks && !Cel.muurRechts)
stream << " ";
else if(!Cel.muurLinks)
stream << " X";
else if(!Cel.muurRechts)
stream << "X ";
else if(!Cel.muurOnder || !Cel.muurBoven) //important: if left/right is closed, but top or down isnt'
stream << "X X";
else
stream << "XXX";
}
stream << endl;
for(const Cel& Cel: row){
if(!Cel.muurOnder)
stream << "X X";
else
stream << "XXX";
}
stream << endl;
}
stream << endl;
return stream;
}
//My Functions (definition)
Doolhof maakDoolhof(int dimensie);
Cel& getCel(Doolhof& doolhof, Positie positie);
vector<Positie> getGeldigeBuren(Doolhof& doolhof, Positie positie);
void murenWegTussenBuren(Doolhof& doolhof, Positie cel1, Positie cel2);
void genereerDoolhof(Doolhof& doolhof, Positie pos, bool debug);
void debug_output(const Doolhof& doolhof, Positie pos);
//MAIN:
int main() {
//DEBUG MODE, set true to debug
const bool DEBUG = true;
//Dimension of doolhof
int n = 10;
//Variable for Doolhof
Doolhof doolhof;
doolhof = maakDoolhof(n);
//Seeding random function
srand(time(0));
//Random start position
int random_rij = rand() % n;
int random_kolom = rand() % n;
Positie startPos;
startPos.rij = random_rij;
startPos.kolom = random_kolom;
//Launch function to generate doolhof
genereerDoolhof(doolhof, startPos, DEBUG);
//Printing out doolhof
cout << doolhof;
return 0;
}
//My Functions (declaration)
//
//Function to show each iteration
//param doolhof: const Doolhof& -> Reference to the vector doolhof
//param pos: Positie -> Position of the current location
void debug_output(const Doolhof& doolhof, Positie pos) {
int rij = 0;
for(auto row: doolhof){
for(const Cel& Cel: row){
if(!Cel.muurBoven)
cout << "X X";
else
cout << "XXX";
}
cout << endl;
int kolom = 0;
for(const Cel& Cel: row){
char sep = ' ';
if (pos.rij == rij && pos.kolom == kolom) sep = 'S';
if(!Cel.muurLinks && !Cel.muurRechts)
cout << " " << sep << " ";
else if(!Cel.muurLinks)
cout << " " << sep << "X";
else if(!Cel.muurRechts)
cout << "X" << sep << " ";
else if(!Cel.muurOnder || !Cel.muurBoven) //important: if left/right is closed, but top or down isnt'
cout << "X" << sep << "X";
else {
sep = 'X';
if (pos.rij == rij && pos.kolom == kolom) sep = 'S';
cout << "X" << sep << "X";
}
kolom++;
}
cout << endl;
for(const Cel& Cel: row){
if(!Cel.muurOnder)
cout << "X X";
else
cout << "XXX";
}
cout << endl;
rij++;
}
cout << endl;
return;
}
//Creates the bases of a doolhof (no cells connected yet)
//param dimensie: Int -> Dimension of the doolhof
//return: type=Doolhof -> Returning the whole Doolhof
//Signature: Int -> Doolhof
Doolhof maakDoolhof(int dimensie) {
//Vector for Doolhof
Doolhof doolhof;
for (int i = 0; i < dimensie; i++) {
//Vector to hold all the cels making one row
vector<Cel> row;
for (int j = 0; j < dimensie; j++) {
//Creating a Cel and it's properties
Cel cel;
cel.muurLinks = true;
cel.muurRechts = true;
cel.muurBoven = true;
cel.muurOnder = true;
cel.bezocht = false;
//Adding cel to row
row.push_back(cel);
}
//Adding row to whole doolhof
doolhof.push_back(row);
}
//Returning doolhof
return doolhof;
}
//Returns Cell at specified position
//param doolhof: Doolhof& -> Reference to the Doolhof vector
//param positie: Positie -> Position of Cell to return
//return: type=Cel& -> Reference to the cell at specified position
Cel& getCel(Doolhof& doolhof, Positie positie) {
//Parameters to local variables
int row = positie.rij;
int col = positie.kolom;
return doolhof[row][col];
}
//Returns all the valid cells around the specified position
//Cells laying out of the maze ain't valid for example
//param doolhof: Doolhof& -> Reference to the Doolhof vector
//param positie: Positie -> Positie of the cell to check
//return: type=vector<Positie> -> Vector containing all valid positions
vector<Positie> getGeldigeBuren(Doolhof& doolhof, Positie positie) {
//Vector holding valid positions of cells
vector<Positie> valid;
//Dimension
int dimension = doolhof[0].size();
//Position to add
Positie pos;
//Checking for horizontal cells
//Check if left is valid
if (positie.kolom - 1 >= 0 &&
positie.kolom < dimension &&
positie.rij < dimension &&
positie.rij >= 0) {
pos.rij = positie.rij;
pos.kolom = positie.kolom -1;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
//Check if right is valid
if (positie.kolom + 1 < dimension &&
positie.kolom >= 0 &&
positie.rij < dimension &&
positie.rij >= 0) {
pos.rij = positie.rij;
pos.kolom = positie.kolom +1;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
//Checking for vertical cells
//Check if upper is valid
if (positie.rij - 1 >= 0 &&
positie.rij < dimension &&
positie.kolom < dimension &&
positie.kolom >= 0) {
pos.rij = positie.rij -1;
pos.kolom = positie.kolom;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
//Check if bottom is valid
if (positie.rij + 1 < dimension &&
positie.rij >= 0 &&
positie.kolom < dimension &&
positie.kolom >= 0) {
pos.rij = positie.rij +1;
pos.kolom = positie.kolom;
//Getting cel
Cel cel = getCel(doolhof, pos);
if(!cel.bezocht) valid.push_back(pos);
}
return valid;
}
//Takes away walls between specific cells
//param doolhof: Doolhof& -> Reference to the doolhof-vector
//param cel1: Positie -> Position of the first cell
//param cel2: Positie -> Position of the second cell
//return: void
void murenWegTussenBuren(Doolhof& doolhof, Positie cel1, Positie cel2) {
//Variable for cells we're talking about
Cel cel_a = getCel(doolhof, cel1);
Cel cel_b = getCel(doolhof, cel2);
//Case 1: HORIZONTAL -> cel2 <> cel1
if (cel1.rij == cel2.rij &&
cel1.kolom == cel2.kolom +1) {
cel_a.muurLinks = false;
cel_b.muurRechts = false;
}
//Case 2: HORIZONTAL -> cel2 <> cel1
else if (cel2.rij == cel1.rij &&
cel2.kolom == cel1.kolom +1) {
cel_a.muurRechts = false;
cel_b.muurLinks = false;
}
//Case 3: VERTICAL -> cel1 ^ cel2
else if (cel1.rij == cel2.rij +1 &&
cel1.kolom == cel2.kolom) {
cel_a.muurBoven = false;
cel_b.muurOnder = false;
}
//Case 4: VERTICAL -> cel2 ^ cel1
else if (cel1.rij +1 == cel2.rij &&
cel1.kolom == cel2.kolom) {
cel_a.muurOnder = false;
cel_b.muurBoven = false;
}
//Case x: ERROR, just return
else return;
//Setting the cell-values back in doolhof
getCel(doolhof, cel1) = cel_a;
getCel(doolhof, cel2) = cel_b;
return;
}
//Generates the final doolhof (takes away walls & connects cells,...)
//param doolhof: Doolhof& -> Reference to the doolhof
//param positie: Positie -> Position to do recursion on
//param debug: Bool -> Prints iteration-steps when true
void genereerDoolhof(Doolhof& doolhof, Positie pos, bool debug) {
//Initial cel current cell
Positie currentCel = pos;
//If debug mode is on
if (debug) debug_output(doolhof, pos);
//Vector holding positions of unvisited neighbours of cell
vector<Positie> unvisited;
unvisited = getGeldigeBuren(doolhof, currentCel);
if (unvisited.size() > 0) {
//Randomly unvisited neighbours
int r = rand() % unvisited.size();
Positie chosen;
chosen = unvisited[r];
//Push the current cell to the stack
myStack.push(currentCel);
//Remove wall between current and chosen
murenWegTussenBuren(doolhof, currentCel, chosen);
//Make chosen current and make it visited
currentCel = chosen;
getCel(doolhof, currentCel).bezocht = true;
//Recursive call
return genereerDoolhof(doolhof, currentCel, debug);
} else {
if (myStack.size() != 0) {
myStack.pop();
currentCel = myStack.top();
return genereerDoolhof(doolhof, currentCel, debug);
};
}
}