心血来潮,写了个走迷宫的程序

 前几天一直在琢磨怎么生成一个迷宫,不过琢磨来琢磨去也没有想出来,现在自己有个想法了,不过方法太直观了,我用控制台模式生成了一个,不过居然是一个非常简单的迷宫,简单到你可以一眼看出来出路,有时甚至只有一条路。算了,还是去看别人的代码算了,还好,找到一个人的源代码,可以随机生成一个迷宫,看了一下,还不错,迷宫的形状什么的都还挺好的,而且貌似他也没有采用什么高深的算法,只是用了不断的随机选取方向,然后用一个deque的结构保存访问过的节点,处理访问已经走过的点的方法有点看不懂,还在研究之中。 不过算了,最后决定自己写一个走随机迷宫的程序补偿一下。其实这个程序可以说是大二数据结构的上机作业,只怪当初自己太懒了,让别人罩自己,一直没有写过。。。。。。 不用说,典型的普遍的走迷宫算法基本都是通过栈数据结构实现的,也有人用图,但是这是他们在建立迷宫的时候就已经把迷宫的表现方式表现为图了,因此在走迷宫的时候他们就可以采用深度优先搜索或广度优先来实现,这样也就失去了探索一个未知迷宫的乐趣。 首先,肯定是要实现一个栈的数据结构,并给出操作这个数据结构的方法,其实你也可以用stl的vector或stack来实现,呵呵,我是自己写了一个栈的模版。走迷宫过程不会出现迷路现象,肯定可以走出去,并找到最优路径。 // WinMaze.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "WinMaze.h" #include "maze.h" #include "MyStack.h" using namespace serial; #define MAX_LOADSTRING 100 #define WM_ENDROUND WM_USER+2 //定时器1 #define IDEVENT_RUN 1 //定时器2 #define IDEVENT_BESTPATH 2 /************************************************************************ ******寻找下一个可移动的方向,0表示无可移动方向,1表示向东移动,******** ******2表示向南移动,3表示向西移动,4表示向北移动,若有多个移动******** ******方向,则优先选取向东方向,即南向次之,北向更次之,最后为西****** ********************************************************************/ int FindNext(int , int); //迷宫数组,scale在mymaze.h中定义为const int . char maze[ scale ][ scale ]; //起始位置和结束位置 pair start; pair end; // 用来保存路径的list deque pathlst; void GetFinalPath(deque &); //位置的结构体 struct pos { int i; //纵坐标 int j; //横坐标 BOOL isWall; //是否是墙 BOOL isVisited; //是否被访问过 } targetpos[scale][scale]; //扩展的迷宫位置数组 //恢复原始未访问状态 void reset(pos [][scale]); //位置栈 MyStack stack; //首先在winmain中初始化迷宫数组和位置栈,以及其它相关数据 int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { srand( time( 0 ) ); initMaze( maze ); generateMaze( maze); for ( int i = 0; i < scale ; i ++ ) { for ( int j = 0; j < scale ; j ++ ) { targetpos[i][j].i = i; targetpos[i][j].j = j; if (maze[i][j] == '#') { targetpos[i][j].isWall = TRUE; } else targetpos[i][j].isWall = FALSE; targetpos[i][j].isVisited = FALSE; } } //求出入口和出口 for ( int k = 0; k < scale; k ++ ) { if (maze[k][0] != '#') { start.first = k; start.second = 0; break; } } for ( k = 0; k < scale ; k ++ ) { if (maze[k][scale - 1] != '#') { end.first = k; end.second = scale - 1; break; } } //初始化栈,并把入口进栈 stack.iStackSize = 100; initstack(stack); pos startpos; startpos.i = start.first; startpos.j =start.second; startpos.isWall = FALSE; Push(stack, startpos); .............................................................. ................................................................. } //自己这个函数写的风格自己都觉得很恶心。。。。以后再修改吧。。。。。 int FindNext(int i, int j) { //下一步可走的方向数量 int directions = 0; if ( !targetpos[i][j + 1].isWall && j < scale - 1 ) { //东面可走 directions += 1; } if ( !targetpos[i - 1][j].isWall && i > 0 ) { directions += 1;//北面可走 } if ( !targetpos[i + 1][j].isWall && i < scale - 1 ) { directions += 1;//南面可走 } if ( !targetpos[i][j - 1].isWall && j > 0 ) { directions += 1;//西面可走 } if ( directions == 1 && j > 0 ) { return 0;//倘若只有一个方向,则这个方向必然为刚才走过来的方向,则返回0,表明这个位置不 //可往下走, } else {//若有大于一个的方向,若东面可走并且还没有被访问过,则优先向东,否则依次换方向 if ( !targetpos[i][j + 1].isWall && j < scale - 1 ) { if (!targetpos[i][j+1].isVisited) { return 1; } } if ( !targetpos[i - 1][j].isWall && i > 0 ) { if (!targetpos[i - 1][j].isVisited) { return 4; } } if ( !targetpos[i + 1][j].isWall && i < scale - 1 ) { if (!targetpos[i + 1][j].isVisited) { return 2; } } if ( !targetpos[i][j - 1].isWall && j > 0 ) { if (!targetpos[i][j - 1].isVisited) { return 3; } } } return 0; } //用一个deque结构取得最优路径,探索走到出口后,栈中保存的位置必然为最优路径的位置和顺序。 void GetFinalPath(deque & lst) {//12为一个迷宫单元的长宽。。。用于计算坐标 pos tmppos; POINT pt; while (stack.base != stack.top) { pop(stack, tmppos); pt.x = tmppos.j * 12; pt.y = tmppos.i * 12; lst.push_front(pt); } pt.x = end.second * 12; pt.y = end.first * 12; lst.push_front(pt); } //恢复原始状态 void reset(pos ps[][scale]) { for ( int i = 0; i < scale ; i ++ ) { for ( int j = 0; j < scale ; j ++ ) { ps[i][j].i = i; ps[i][j].j = j; if (maze[i][j] == '#') { ps[i][j].isWall = TRUE; } else ps[i][j].isWall = FALSE; ps[i][j].isVisited = FALSE; } } } 好了,准备完毕,下一步就是在timer中探索迷宫并计算当前探索坐标了。主要思想为: 1。首先取出栈顶元素,并计算出栈顶元素所表示点的坐标,并赋值给探索的位置; 2。然后把跟栈顶相通的点其中一个压入栈中(调用findnext函数),如果findnext返回0,即当前无可前进道路,也即只有回头路了,则当前栈顶元素出栈,并把出栈元素所代表的点标记为不可访问,转1 3。若当前栈顶元素为出口,算法停止。代码如下所示: case WM_TIMER: { time += 100; switch(wParam) { //探索未知迷宫的定时器事件 case IDEVENT_RUN: { pos currentpos; GetTop(stack,currentpos); bx = (currentpos.j) * cxSource ; by = (currentpos.i) * cySource ; //当前位置已经访问 targetpos[currentpos.i][currentpos.j].isVisited = TRUE; pos tmppos; switch( FindNext(currentpos.i, currentpos.j)) { case 0: { pop(stack, tmppos);//不可访问出栈 targetpos[tmppos.i][tmppos.j].isWall = TRUE ; } break; case 1: { tmppos.i = currentpos.i ; tmppos.j = currentpos.j + 1; //可访问进站 Push(stack, tmppos); } break; case 2: { tmppos.i = currentpos.i + 1; tmppos.j = currentpos.j ; Push(stack, tmppos); } break; case 3: { tmppos.i = currentpos.i ; tmppos.j = currentpos.j - 1; Push(stack, tmppos); } break; case 4: { tmppos.i = currentpos.i - 1; tmppos.j = currentpos.j ; Push(stack, tmppos); } break; default: break; } InvalidateRect(hWnd, &rect, TRUE); } break; case IDEVENT_BESTPATH: //这个定时器事件表示找到最优路径后的事件 { bx = pathlst[index].x; by = pathlst[index].y; index += 1; if (index == pathlst.size() ) { KillTimer(hWnd, IDEVENT_BESTPATH); InvalidateRect(hWnd, &rect, TRUE); } InvalidateRect(hWnd, &rect, TRUE); } break; default: break; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值