迷宫生成及深度优先搜索遍历迷宫(OpenGL)

  其实以前就写过一个迷宫的程序和DFS遍历,不过弄丢了,前几天闲就重写了一下。欢迎交流和拍砖。有很多不足的地方也希望大家多指正。

  迷宫生成的算法来自《计算机图形学》,也就是这本书:

  生成迷宫的算法描述如下:

  由于表示墙使用了up_wall和left_wall两个矩阵,所以格子的数量要比能显示出来的多一行一列,否则屏幕最下边和最右边是没有墙的。虽然可以后面画上,不过我选择这样。

  对于迷宫的遍历使用DFS,另外由于使用了一个visited矩阵表示每个格子是否已经访问过,所以即使迷宫里存在环也没有任何影响,不会死循环。

  

  另外当时不知道glutPostRedisplay()这玩意儿,所以很蠢的把遍历的过程设成了DisplayFunc来看遍历的过程。

  生成迷宫及DFS遍历的代码如下:

  1 #include <iostream>
  2 #include <fstream>
  3 #include <stack>
  4 #include <GL/gl.h>
  5 #include <GL/glu.h>
  6 #include <GL/glut.h>
  7 #include <cstdlib>
  8 using namespace std;
  9
 10 /*Constant And Structures*/
 11 const int SCREEN_WIDTH = 1200;
 12 const int SCREEN_HEIGHT = 600;
 13 const int BLOCK_SIZE = 10;
 14
 15 const int BLOCK_VER_NUM = (SCREEN_WIDTH / BLOCK_SIZE) + 1;
 16 const int BLOCK_HOR_NUM = (SCREEN_HEIGHT / BLOCK_SIZE) + 1;
 17
 18 bool up_wall[BLOCK_VER_NUM][BLOCK_HOR_NUM];
 19 bool left_wall[BLOCK_VER_NUM][BLOCK_HOR_NUM];
 20 bool visited[BLOCK_VER_NUM][BLOCK_HOR_NUM];
 21
 22 const int wall_size = 1;
 23
 24 enum Dir
 25 {
 26     _up = 0,
 27     _left = 1,
 28     _right = 2,
 29     _down = 3,
 30     _none = 4
 31 };
 32 const int DIR_SUM = 3;
 33
 34 struct Pos
 35 {
 36     int x, y;
 37     Pos(int xx, int yy)
 38     {
 39         x = xx;
 40         y = yy;
 41     }
 42     Pos()
 43     {
 44         x = 0;
 45         y = 0;
 46     }
 47     Pos(const Pos& p)
 48     {
 49         x = p.x;
 50         y = p.y;
 51     }
 52     Pos& operator =(const Pos& p)
 53     {
 54         x = p.x;
 55         y = p.y;
 56     }
 57
 58     bool operator ==(const Pos& p)
 59     {
 60         return (x == p.x) && (y == p.y);
 61     }
 62 };
 63
 64 class Path : public stack<Pos>
 65 {
 66 public:
 67     Path() : stack<Pos>()
 68     {}
 69     const deque<Pos>& _Get_container()
 70     {
 71         return c;
 72     }
 73 };
 74
 75 //For Build Puzzle
 76 stack<Pos> pos;
 77 stack<Pos> temp;
 78
 79 Path path;
 80 Pos entryPuzzle;
 81 Pos entrancePuzzle;
 82 bool arrive;
 83
 84
 85
 86 /*Function*/
 87 void myDisplay()
 88 {
 89     glClear(GL_COLOR_BUFFER_BIT);
 90     glBegin(GL_POINTS);
 91
 92     for(int i = 0; i < SCREEN_WIDTH; ++i)
 93     {
 94         for(int j = 0; j < SCREEN_HEIGHT; ++j)
 95         {
 96             int bx = i / BLOCK_SIZE;
 97             int by = j / BLOCK_SIZE;
 98
 99             // //cout << "Opering Cell: " << bx << "," << by << endl;
100             if(up_wall[bx][by])
101             {
102                 if(j % BLOCK_SIZE < wall_size)
103                 {
104                     ////cout << "Put Pix at " << i << "," << j << endl;;
105                     glVertex2d(i, j);
106                 }
107             }
108             if(left_wall[bx][by])
109             {
110                 if(i % BLOCK_SIZE < wall_size)
111                 {
112                     // //cout << "Put Pix at " << i << "," << j << endl;
113                     glVertex2d(i, j);
114                 }
115             }
116         }
117     }
118
119     glEnd();
120     glFlush();
121     //cout << "Render Over\n";
122 }
123
124 void DisplayTraverse()
125 {
126     glClear(GL_COLOR_BUFFER_BIT);
127     glBegin(GL_POINTS);
128
129     glColor3f(0.0f, 0.0f, 0.0f);//Map Color Black
130     //glPointSize(1.0);
131     for(int i = 0; i < SCREEN_WIDTH; ++i)
132     {
133         for(int j = 0; j < SCREEN_HEIGHT; ++j)
134         {
135             int bx = i / BLOCK_SIZE;
136             int by = j / BLOCK_SIZE;
137
138             // //cout << "Opering Cell: " << bx << "," << by << endl;
139             if(up_wall[bx][by])
140             {
141                 if(j % BLOCK_SIZE < wall_size)
142                 {
143                     ////cout << "Put Pix at " << i << "," << j << endl;;
144                     glVertex2d(i, j);
145                 }
146             }
147             if(left_wall[bx][by])
148             {
149                 if(i % BLOCK_SIZE < wall_size)
150                 {
151                     // //cout << "Put Pix at " << i << "," << j << endl;
152                     glVertex2d(i, j);
153                 }
154             }
155         }
156     }
157     glEnd();
158
159     glColor3f(0.0f, 0.0f, 1.0f);//Map Color Black
160     //glPointSize(2.0);
161     glBegin(GL_LINE_STRIP);
162
163     const int off = BLOCK_SIZE / 2;
164
165     auto dq = path._Get_container();
166     for(auto it : dq)
167     {
168         glVertex2d(it.x * BLOCK_SIZE + off, it.y * BLOCK_SIZE + off);
169     }
170
171     glEnd();
172
173
174     glFlush();
175 }
176
177 bool canbeDestroy(int x, int y)
178 {
179     //cout << "Detect CanbeDestroy: " << x << "," << y << endl;
180     bool succ = true;
181     if(x < 0 || x >= BLOCK_VER_NUM - 1 || y < 0 || y >= BLOCK_HOR_NUM - 1)
182     {
183         return false;
184     }
185
186     succ = left_wall[x][y] && up_wall[x][y] && left_wall[x + 1][y] && up_wall[x][y + 1];
187     //if(succ) //cout << "And Succ\n\n";
188     //else //cout << "And False\n\n";
189     return succ;
190 }
191
192 void Proc(Pos& position)
193 {
194     //cout << "Procing" << position.x << "," << position.y << endl;
195     if(position.x < 0 || position.x >= BLOCK_VER_NUM || position.y < 0 || position.y >= BLOCK_HOR_NUM)
196         return;
197     stack<Pos> temp;
198
199     //Find Neighbour Who can be access
200     for(int i = 0; i < 4; ++i)
201     {
202         switch(i)
203         {
204         case _up:
205         {
206             if(canbeDestroy(position.x, position.y - 1))
207             {
208                 temp.emplace(position.x, position.y - 1);
209             }
210         }break;
211         case _down:
212         {
213             if(canbeDestroy(position.x, position.y + 1))
214             {
215                 temp.emplace(position.x, position.y + 1);
216             }
217         }break;
218         case _left:
219         {
220             if(canbeDestroy(position.x - 1, position.y))
221             {
222                 temp.emplace(position.x - 1, position.y);
223             }
224         }break;
225         case _right:
226         {
227             if(canbeDestroy(position.x + 1, position.y))
228             {
229                 temp.emplace(position.x + 1, position.y);
230             }
231         }break;
232         default:break;
233         }
234     }
235
236     if(temp.size() == 0)//No valid target
237         return;
238
239     //Have valid target, and random choose one
240     int size = temp.size();
241     int tar = rand() % size;
242     //cout << "Select " << tar + 1 << " ops of " << size << endl;
243     Pos next;
244     /*int i = 0;
245     while(!temp.empty())
246     {
247         if(i++ == tar)
248         {
249             next = temp.top();
250             temp.pop();
251         }
252
253         //if(!visited[temp.top().x][temp.top().y])
254         pos.push(temp.top());
255         temp.pop();
256     }*/
257     for(int i = 0; i < size; ++i)
258     {
259         if(i == tar)
260         {
261             next = temp.top();
262             temp.pop();
263         }
264         else
265         {
266             //if(!visited[temp.top().x][temp.top().y])
267             //pos.push(temp.top());
268             temp.pop();
269         }
270     }
271     pos.push(position);
272
273     if(next.y == position.y - 1)
274         up_wall[position.x][position.y] = false;
275     else if(next.y == position.y + 1)
276         up_wall[position.x][position.y + 1] = false;
277     else if(next.x == position.x - 1)
278         left_wall[position.x][position.y] = false;
279     else if(next.x == position.x + 1)
280         left_wall[position.x + 1][position.y] = false;
281     else
282     {
283
284     }
285
286     //visited[next.x][next.y] = true;
287     //cout << "Move To " << next.x << "," << next.y << endl;
288     //myDisplay();
289     Proc(next);
290 }
291
292 void MakePuzzle()
293 {
294     while(!pos.empty())
295     {
296         Pos curpos = pos.top();
297         pos.pop();
298         //visited[curpos.x][curpos.y] = true;
299         Proc(curpos);
300     }
301
302
303     cout << "MakePuzzle Over.\n";
304 }
305
306 void myInit()
307 {
308     /*
309     Output Info
310     */
311     //cout << "Screen Size: " << SCREEN_WIDTH << "*" << SCREEN_HEIGHT << endl;
312     //cout << "Block Size: " << BLOCK_SIZE << endl;
313     //cout << "Puzzle Size: " << BLOCK_VER_NUM << "*" << BLOCK_HOR_NUM << endl;
314     //cout << "Wall Size: " << wall_size << endl;
315
316
317     glClearColor((float)0x66 / 0x100, (float)0xcc / 0x100, 1.0, 0.0);
318     glColor3f(0.0f, 0.0f, 0.0f);//Map Color Black
319     //glPointSize(1.0);
320     glMatrixMode(GL_PROJECTION);
321
322     glLoadIdentity();
323     gluOrtho2D(0.0, (GLdouble)SCREEN_WIDTH, 0.0, (GLdouble)SCREEN_HEIGHT);
324     glViewport(0.0, SCREEN_WIDTH, 0.0, SCREEN_HEIGHT);
325
326     for(int i = 0; i < BLOCK_VER_NUM; ++i)
327     {
328         for(int j = 0; j <  BLOCK_HOR_NUM; ++j)
329         {
330             up_wall[i][j] = true;
331             left_wall[i][j] = true;
332             visited[i][j] = false;
333         }
334     }
335
336     cout << "Display after init\n";
337     myDisplay();
338
339     pos.emplace(BLOCK_VER_NUM / 2, BLOCK_HOR_NUM / 2);
340     cout << "myInit Over.\n";
341 }
342
343 void TraverseDFS(const Pos& p)
344 {
345     cout << "Travering " << p.x << ", " << p.y << endl;
346     path.push(p);
347     visited[p.x][p.y] = true;
348     DisplayTraverse();
349     if(entrancePuzzle == p)
350     {
351         arrive = true;
352         return;
353     }
354
355     if((p.x > 0) && !left_wall[p.x][p.y] && !visited[p.x - 1][p.y])//left
356     {
357         Pos next(p.x - 1, p.y);
358         TraverseDFS(next);
359         return;
360     }
361     if((p.x < BLOCK_VER_NUM - 1) && !left_wall[p.x + 1][p.y] && !visited[p.x + 1][p.y])//right
362     {
363         Pos next(p.x + 1, p.y);
364         TraverseDFS(next);
365         return;
366     }
367     if((p.y > 0) && !up_wall[p.x][p.y] && !visited[p.x][p.y - 1])//up
368     {
369         Pos next(p.x, p.y - 1);
370         TraverseDFS(next);
371         return;
372     }
373     if((p.y < BLOCK_HOR_NUM - 1) && !up_wall[p.x][p.y + 1] && !visited[p.x][p.y + 1])//down
374     {
375         Pos next(p.x, p.y + 1);
376         TraverseDFS(next);
377         return;
378     }
379
380     path.pop();
381 }
382
383 void TraverseInit()
384 {
385     entryPuzzle.x = 0;
386     entryPuzzle.y = rand() % (BLOCK_HOR_NUM - 1);
387     entrancePuzzle.x = BLOCK_VER_NUM - 2;
388     entrancePuzzle.y = rand() % (BLOCK_HOR_NUM - 1);
389
390     cout << "Generated\nEntry: " << entryPuzzle.x << ", " << entryPuzzle.y << endl;
391     cout << "Entrance: " << entrancePuzzle.x << ", " << entrancePuzzle.y << endl;
392
393     path.push(entryPuzzle);
394     visited[entryPuzzle.x][entryPuzzle.y] = true;
395     arrive = false;
396 }
397
398 void Traverse()
399 {
400     while(!path.empty() && !arrive)
401     {
402         Pos& cur = path.top();
403         path.pop();
404         TraverseDFS(cur);
405     }
406     if(arrive)
407         cout << "Arrived.\n";
408     else
409         cout << "Something Wrong, Not arrive.";
410 }
411
412 int main(int argc, char* argv[])
413 {
414     glutInit(&argc, argv);
415     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
416     glutInitWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT);
417     glutInitWindowPosition(0, 0);
418     glutCreateWindow("Puzzle");
419     glutDisplayFunc(Traverse);
420
421     myInit();
422     MakePuzzle();
423     TraverseInit();
424     glutMainLoop();
425
426     return 0;
427 }

   代码中myInit函数用来初始化各个矩阵。之后是MakePuzzle构造迷宫。构造迷宫的过程使用了一个栈并且是用Proc函数递归调用来生成迷宫的。现在想想其实可以写成完全的递归或者迭代的,不过当时写着顺手就这么写了。canbeDestroy函数即是判断一个格子是否有四堵完整的墙,同时考虑了边界。

  之后就是DFS遍历了,TraverseInit函数在迷宫最左边随机选取一点作为起点,最右边随机选择一点作为终点。然后起点压栈,进入主循环也就是Traverse函数开始遍历。Traverse还是使用了递归+迭代的方式,不断递归直到进入死路,然后弹栈重新递归。

  最后,最上面俩函数myDisplay和DisplayTraverse,前者是用来画迷宫的,后者则是迷宫+DFS的路径。另外我画迷宫是一个像素一个像素去判断是否在迷宫的墙上,是就画不是就不画,这样其实效率很低,完全可以遍历每行每列用GL_LINES去画的。人懒没药医啊。

运行情况(由于宽度1200截图出来显示效果不好所以我改成了800):

  另外至于生成迷宫是叫MakePuzzle,完全是因为我英语不好并且写这东西的时候完全是在无网络的情况下所以随便想了个单词。

时间: 2024-12-19 04:23:57

迷宫生成及深度优先搜索遍历迷宫(OpenGL)的相关文章

迷宫寻址中深度优先搜索的递归和非递归算法比较

巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo) 本文只探究迷宫寻址中深度优先搜索的递归和非递归算法比较,其他相关代码详见<迷宫问题(巧若拙)>http://blog.csdn.net/qiaoruozhuo/article/details/41020745 深度优先搜索的递归算法是很容易实现的,只需设置一个驱动函数,然后递归调用子函数就可以了. 代码如下: int DeepSearchWay()//寻找路径:深度搜索 { CopyMiGong

数据结构--图--图的数组存储表示,深度优先搜索遍历和广度优先搜索遍历

图有四种存储结构:数组,邻接表,十字链表,邻接多重表.下面以数组为存储结构来实现图的深度优先搜索遍历和广度优先搜索遍历.其中广度优先搜索遍历中有用到STL中的queue,注意头文件的包含.具体代码如下: //图的数组(邻接矩阵)存储表示和深度优先遍历 const int MAX_VERTEX_NUM=20; //最大顶点数 typedef enum {DG,DN,UDG,UDN} GraphKind ;//(有向图,有向网,无向图,无向网) typedef int VRType; typedef

深度优先搜索(迷宫救人最短路径)

1 import java.util.Scanner; 2 3 public class One { 4 //n,m为迷宫的行列范围,p,q是某人迷路所在地点,min用于记录走到终点最小路径的步数 5 public static int n,m,p,q,min=9999; 6 //数组a是迷宫,1代表有障碍物,数组d用于移动方向(右.下.左.上),数组book用于标记当前位置是否在路径中 7 public static int a[][]=new int[51][51],book[][]=new

DFS(深度优先搜索遍历有向图)-03-有向图-太平洋大西洋水流问题

给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度.“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界. 规定水流只能按照上.下.左.右四个方向流动,且只能从高到低或者在同等高度上流动. 请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标. 提示: 输出坐标的顺序不重要m 和 n 都小于150 示例: 给定下面的 5x5 矩阵: 太平洋 ~ ~ ~ ~ ~ ~ 1 2 2 3 (5) * ~ 3 2 3 (4) (4) * ~ 2

基于深度及广度优先搜索的迷宫问题的演示

1 时间复杂度分析 由于该图采用邻接矩阵存储,整个算法遍历的过程所花费的时间复杂度为该矩阵的N(row*col).而由于其需要分别访问已经定位,需要进行分别2次操作,如下: visited = new bool[col*row];//访问标记 for (i=0; i<row; i++) for (j=0; j<col; j++) visited[i*col+j] = false;//初始为未访问状态 position = new POSITION[col*row]; for (i=0; i&l

图的遍历之 深度优先搜索和广度优先搜索

本章会先对图的深度优先搜索和广度优先搜索进行介绍,然后再给出C/C++/Java的实现. 目录 1. 深度优先搜索的图文介绍 1.1 深度优先搜索介绍 1.2 深度优先搜索图解 2. 广度优先搜索的图文介绍 2.1 广度优先搜索介绍 2.2 广度优先搜索图解 3. 搜索算法的源码 深度优先搜索的图文介绍 1. 深度优先搜索介绍 图的深度优先搜索(Depth First Search),和树的先序遍历比较类似. 它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然

图的遍历之深度优先搜索和广度优先搜索

转自:http://www.cnblogs.com/skywang12345/ 深度优先搜索的图文介绍 1. 深度优先搜索介绍 图的深度优先搜索(Depth First Search),和树的先序遍历比较类似. 它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到. 若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访

castle problem——(深度优先搜索,递归实现和stack实现)

将问题的各状态之间的转移关系描述为一个图,则深度优先搜索遍历整个图的框架为:Dfs(v) {if( v 访问过)return;将v标记为访问过;对和v相邻的每个点u: Dfs(u);}int main() {while(在图中能找到未访问过的点 k)Dfs(k);} 4例题:百练2815 城堡问题? 右图是一个城堡的地形图.请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大.城堡被分割成m×n(m≤50,n≤50)个方块,每个方块可以有0~4面墙.5输入输出? 输入? 程序从标准输入设备

深度优先搜索入门:POJ1164城堡问题(递归、用栈模拟递归)

将问题的各状态之间的转移关系描述为一个图,则深度优先搜索遍历整个图的框架为:Dfs(v) {if( v 访问过)return;将v标记为访问过;对和v相邻的每个点u: Dfs(u);}int main() {while(在图中能找到未访问过的点 k) Dfs(k);} 例题: POJ1164 The Castle Description 1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####---#####---#-