迷宫算法生成模式

时间:2017-11-19 23:48:55

标签: c++ recursion backtracking maze

我想使用递归回溯在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()只需将所有单元格放入迷宫中,并使用单元格默认值(所有墙都为真并设置,并由 递归是错误的)

  • 切尔&安培; getCel()你可以在迷宫中给出一个位置/坐标,并且将返回单元格 - 包括它的属性 -
  • vector getGeldigeBuren()此函数获取单元格的所有有效邻居,以确保算法保留在单元格中 迷宫;并且它不包括“迷宫之外的邻居”
  • void murenWegTussenBuren()每个单元格由3x3 X组成,此函数需要两个单元格并连接它们。如果找到cellA 在cellB右边,cellA.wallLeft采取了一种方式,并在cellB.wallRight 被带走(设置为假),因此它们已连接。
  • void genereerDoolhof()递归回溯算法,这个函数应该混合所有以前的函数来制作一个漂亮的迷宫。

我认为我非常接近实施迷宫算法,我只需要最后一点逻辑并帮助完全解决它。我非常感谢你的帮助!

函数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);
        };
    }

}

0 个答案:

没有答案