深度优先搜索生成迷宫

来源:互联网 发布:百会云计算 编辑:程序博客网 时间:2024/05/06 16:56

前些天逛书店,发现一本叫做<<opengl超级宝典第5版>>的书,买了下来回家慢慢看.感觉这本书比<<opengl编程指南>>更适合入门学习,因为里面有许多例子.后来才知道,这本书就是所谓"opengl蓝宝书".看了这本书,许多看红宝书时不明白的地方突然就明白了,可能是因为这本书翻译的质量更好,或者说这本书解释得更具体.


无意间发现了一个博客,http://blog.csdn.net/jiangcaiyang123.该博客主人还是个学生,技术却不错.代码写得清晰,注重复用,在学校写的代码就用上了泛型和跨平台,对opengl 和 dx的理解也比我强..跟他比起来,我很惭愧.上班这些年,总有许多生活上的琐事,让自己学习时间并不充足.即使在学生时代时间充足的时候,自己的水平也比人家差的太远.我不禁感慨时间飞逝,惋惜以往浪费的时间.


那个博客里有个opengl 3d的迷宫,我最近也在学习opengl,打算不参考其他人代码的前提下,自己也搞一个.
今天就弄个迷宫自动生成的控制台程序,过些天想办法移植到 opengl上.

关于迷宫自动生成参考了一些资料,主要是维基百科

http://en.wikipedia.org/wiki/Maze_generation_algorithm

里面介绍了几种常用的算法,我这里的代码暂时只参考了深度优先搜索算法.算法本身里面描述的比较清楚 ,不再赘述.在过程
中遇到了一个转不过弯的地方,记录如下.

迷宫的存储结构是一个2维数组,在采用深度优先搜索的时候,会遍历这个数组的每个元素.
然而,最终迷宫存储的数组,并不是这个数组,而是一个"扩展数组".
即,如果把原数组看作是一个方格,该方格仅代表一个数组元素的话,扩展数组则把这一个方格扩展为9个元素,分别是
左上,正上,右上,左侧,正中,右侧,左下,正下,右下.

这样才能把深度优先搜索的矩阵,与最终的迷宫矩阵建立联系.

就像下面代码 Maze类中的  MazePoint**    m_arrMaze  是最终迷宫的矩阵,

MazePoint** m_arrRaw 是用来做遍历生成路径的辅助矩阵。


现在不太方便具体绘图说明,上面一段话表达不够清晰,但是却是生成迷宫时困扰我时间最长的问题.


直接上代码和截图吧.

Maze.h
#ifndef_MAZE_H_#define_MAZE_H_#include <vector>#defineDEBUG_MAZE_GENERATEstruct MazePoint{int _x,_y;bool _bIsVisisted;MazePoint(){_x = _y = 0;_bIsVisisted = false;_state = E_State_Wall;}MazePoint(int x,int y){_x = x;_y = y;_bIsVisisted = false;}void setCoord(int x,int y){_x = x;_y = y;}void operator = (const MazePoint& pt){_x = pt._x;_y = pt._y;_bIsVisisted = pt._bIsVisisted;}bool IsVisited(){return _bIsVisisted;}void setVisited(bool visited = true){_bIsVisisted = visited;}enum{E_State_Path,E_State_Wall,E_State_Entry,E_State_Dest,E_State_Max,};int _state;};class Maze{protected:intm_nCol,m_nRow,m_nRawCol,m_nRawRow;//generate helperMazePoint**m_arrMaze;MazePoint** m_arrRaw;MazePoint m_ptStart;MazePoint m_ptCur;std::vector<MazePoint> m_ptStack;public:Maze();virtual ~Maze();void initMazeArray(int rownum,int colnum);void printMazeArray();//generate helpervoid autoGenerate();bool isThereUnvisited();bool isThePointInBoundary(int x,int y);void reset();enum{E_Dir_Up,E_Dir_Down,E_Dir_Left,E_Dir_Right,E_Dir_Max,};double random(double start,double end);bool getNeighbor(int &x,int &y);};#endif//_MAZE_H_

Maze.cpp

#include "Maze.h"#include <stdio.h>#include <time.h>#include <stdlib.h>Maze::Maze() :m_nCol(0),m_nRow(0){m_arrRaw = NULL;m_arrMaze = NULL;srand((int)time(0));rand();}Maze::~Maze(){reset();}void Maze::initMazeArray(int rownum,int colnum){//raw datam_nRawRow = rownum;m_nRawCol = colnum;m_arrRaw = new MazePoint*[m_nRawRow];for(int i=0;i<m_nRawRow;i++){m_arrRaw[i] = new MazePoint[m_nRawCol]();for(int j=0;j<m_nRawCol;j++){m_arrRaw[i][j].setCoord(j,i);}}//generated datam_nRow = 2 * rownum + 1;m_nCol = 2 * colnum + 1;m_arrMaze = new MazePoint*[m_nRow];for(int i=0;i<m_nRow;i++){m_arrMaze[i] = new MazePoint[m_nCol]();for(int j=0;j<m_nCol;j++){m_arrMaze[i][j].setCoord(j,i);}}}void Maze::printMazeArray(){printf("Maze Map:\n");for(int i = 0; i < m_nRow; i++ ){for(int j = 0 ;j < m_nCol; j++ ){printf("%d",m_arrMaze[i][j]._state);}printf("\n");}#ifdefDEBUG_MAZE_GENERATEprintf("Raw data:\n");for(int i = 0; i < m_nRawRow; i++ ){for(int j = 0 ;j < m_nRawCol; j++ ){printf("%d",m_arrRaw[i][j]._state);}printf("\n");}#endif}void Maze::autoGenerate(){int curx,cury;int nextx,nexty;curx = cury = 0;m_arrRaw[cury][curx].setVisited(true);m_ptStack.push_back(m_arrRaw[cury][curx]);while(isThereUnvisited()){nextx = curx;nexty = cury;if(getNeighbor(nextx,nexty)){#ifdefDEBUG_MAZE_GENERATEprintf("nextx: %d,nexty: %d\n",nextx,nexty);#endifm_arrRaw[nexty][nextx].setVisited();m_ptStack.push_back(m_arrRaw[nexty][nextx]);//modfiy arrMaze[][] ,mark it passable between (curx,cury) => (nextx,nexty)m_arrMaze[2*cury+1][2*curx+1]._state = MazePoint::E_State_Path;m_arrMaze[2*nexty+1][2*nextx+1]._state = MazePoint::E_State_Path;m_arrMaze[(2*cury+1 + 2*nexty+1)/2][(2*curx+1 + 2*nextx+1)/2]._state = MazePoint::E_State_Path;curx = nextx;cury = nexty;}else if(m_ptStack.size() > 1){m_ptStack.pop_back();curx = m_ptStack[m_ptStack.size()-1]._x;cury = m_ptStack[m_ptStack.size()-1]._y;}else if(m_ptStack.size() == 1){curx = m_ptStack[m_ptStack.size()-1]._x;cury = m_ptStack[m_ptStack.size()-1]._y;m_ptStack.pop_back();}else{//is it possible ?printf("Stack is NULL\n");}}}bool Maze::isThereUnvisited(){for(int i = 0; i < m_nRawRow; i++ ){for(int j = 0 ;j < m_nRawCol; j++ ){if(!m_arrRaw[i][j].IsVisited())return true;}}return false;}bool Maze::isThePointInBoundary(int x,int y){return x >= 0 && x < m_nRawCol &&  y >=0 && y < m_nRawRow;}double Maze::random(double start,double end){return start+(end-start)*rand()/(RAND_MAX + 1.0);}bool Maze::getNeighbor(int &x,int &y){int neighborX[E_Dir_Max];int neighborY[E_Dir_Max];bool isValid[E_Dir_Max];neighborX[E_Dir_Right] = x + 1;neighborY[E_Dir_Right] = y;isValid[E_Dir_Right] = (isThePointInBoundary(neighborX[E_Dir_Right],neighborY[E_Dir_Right])&& !m_arrRaw[neighborY[E_Dir_Right]][neighborX[E_Dir_Right]].IsVisited());neighborX[E_Dir_Left] = x - 1;neighborY[E_Dir_Left] = y;isValid[E_Dir_Left] = (isThePointInBoundary(neighborX[E_Dir_Left],neighborY[E_Dir_Left])&& !m_arrRaw[neighborY[E_Dir_Left]][neighborX[E_Dir_Left]].IsVisited());neighborX[E_Dir_Down] = x;neighborY[E_Dir_Down] = y + 1;isValid[E_Dir_Down] = (isThePointInBoundary(neighborX[E_Dir_Down],neighborY[E_Dir_Down])&& !m_arrRaw[neighborY[E_Dir_Down]][neighborX[E_Dir_Down]].IsVisited());neighborX[E_Dir_Up] = x;neighborY[E_Dir_Up] = y - 1;isValid[E_Dir_Up] = (isThePointInBoundary(neighborX[E_Dir_Up],neighborY[E_Dir_Up])&& !m_arrRaw[neighborY[E_Dir_Up]][neighborX[E_Dir_Up]].IsVisited());//there's no valid direction bool isThereValidDir = false;for(int i=0;i<E_Dir_Max;i++){isThereValidDir = isThereValidDir || isValid[i];}if(!isThereValidDir){return false;}//there's valid direction ,get random oneint randnum = random(0,4);int finalDir = 0;for(int i=0;i<E_Dir_Max;i++){if(isValid[i]){finalDir = i;break;}}while(randnum){randnum--;finalDir++;finalDir = finalDir == E_Dir_Max ? 0 : finalDir;while(!isValid[finalDir]){finalDir++;finalDir = finalDir == E_Dir_Max ? 0 : finalDir;}}x = neighborX[finalDir];y = neighborY[finalDir];return true;}void Maze::reset(){//delete generated dataif( m_arrMaze != NULL){for(int i=0;i<m_nRow;i++){delete[] (m_arrMaze[i]);m_arrMaze[i] = NULL;}delete[] m_arrMaze;m_arrMaze = NULL;}//delete raw dataif( m_arrMaze != NULL){for(int i=0;i<m_nRawRow;i++){delete[] (m_arrRaw[i]);m_arrRaw[i] = NULL;}delete[] m_arrRaw;m_arrRaw = NULL;}}


main.cpp

#include <stdio.h>#include "Maze.h"Maze*pMaze = new Maze();int main(int argc,char** argv){pMaze->initMazeArray(20,20);pMaze->printMazeArray();pMaze->autoGenerate();pMaze->printMazeArray();pMaze->reset();pMaze->initMazeArray(3,8);pMaze->autoGenerate();pMaze->printMazeArray();if(pMaze){delete pMaze;}return 0;}





原创粉丝点击