因为前几天去论坛看到有网友问迷宫算法的问题,所以抽空研究了一下搜索算法.我把很久以前写的
一个走迷宫的程序贴上去了.这个程序比较土,不会判断随机产生的迷宫是否能走通,不是按最短路径搜索,但是,只要是能连通的迷宫就肯定能走出去.呵呵,很土的一个方法,自已瞎琢磨了.
以前的程序算法是这样的:
1.随机产生由0x00和0xff结成的地图
2.从(0,0)点开始进入迷宫
3.因为出口在(MAXX,MAXY),所以搜索方向是 右->下->上->左
4.每走过一个方格把此方格对应的值加1
5.在选择方向时,总是优先选择方格值最小的相邻方格,这样,一个方格走过的次数越多就越不会再次走入, 所以自然而然就会走到(MAXX,MAXY)了
这种算法导致"小人"会在迷宫里不停的走来走去,很多时候是在重复走动,看起来傻傻的(俺喜欢)
为了解决判断迷宫是否能走通问题,和求最短路径问题,我想了很久.
网上有网友说可以用A*算法来探路比较好,我去找了几篇资料,没看太懂,
自已瞎折腾一通,又搞出一个新算法,也不知道学名叫什么,反正结果看起来是对的.呵呵
新的算法是这样的:
1.随机产生由0x00和0xff结成的地图
2.建立一个空的"连通地图方格列表",然后用递归方法去搜索所有与(0,0)相同值的方格,然后把坐格存入"连通地图方格列表"中 在递归时,如果碰到"连通地图方格列表"中已经存在的方格则跳出.这样,就产生了一个"连通地图方格列表",然后只要 判断迷宫入口坐标(0,0)和出口坐标(MAXX,MAXY)是否都在列表时就可以知道是否迷宫能走通了,好简单吧:)
3.把迷宫入口坐标(0,0)的赋值为1,然后用双重循环判断迷宫中每一方格,如果一个方格的值>1且小于255的话,则把相邻 的方格值全部加1,如果某一个相邻方格的值比所在方格值+1还要大的话(因为连通的原因),则把相邻方格设成方格值+1 重复这样做,直到 出口坐标(MAXX,MAXY) 也被赋值为止.
4.现在工作就很简单了,从出口坐标(MAXX,MAXY)开始向上推,逐次递减直到入口坐标(0,0),这样就得到了一个由多个坐标组成的路线表,也就是最短路径了(看起来是的)
5.因为是在老的程序基础上改的,也没有仔细弄,把最短路径经过方格全部设为0,把其它连通的方格则全部设为1, 这样老的程序不做什么修改就OK了.
6.欣赏了几十遍小人走通迷宫的路线,直是简洁,呵呵. 在解决迷宫问题的同时,俺发现判断连通的原理和绘图时填充算法其实是一回事,以后可以自已写填充函数了:)
迷宫问题虽然是小问题,但是扩展开来又可以解决别的问题了,如地图导航之类的.
这个程序及源代码的下载地址在:
- /*
- 这是一个研究最短迷宫寻路算法程序
-
- mail:szluosj@21cn.com
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <dos.h>
- #include <iostream.h>
- const int XSIZE = 60;
- const int YSIZE = 45;
- const int DIE = 255;
- unsigned long count=0;
- unsigned char Map[YSIZE][XSIZE];
- int g_SameAreaList[YSIZE*XSIZE][2]; //相同区域的列表
- int g_iSameAreaCount = 0;
- int g_ShortPathList[YSIZE*XSIZE][2]; //最段的路径点列表
- int g_iShortPathCount = 0;
- int dir[4][2]=
- {
- 1 , 0,
- 0 , 1,
- 0 , -1,
- -1, 0
- };
- int xx=0,yy=0;
- int oldxx=xx,oldyy=yy;
- //枚举一条线段上的所有点
- int LineDDA(int x1,int y1,int x2,int y2,void *p_pData)
- {
- int i,p,n,x,y,tn,j;
- int iIndex = 0;
- int *pData = (int *)p_pData;
-
- if( y1==y2 ) //是一横线
- {
- if(x1>x2)
- {
- x=x2; x2=x1; x1=x;
- }
-
- for (j=x1;j<=x2;j++)
- {
- pData[iIndex] = j;
- pData[iIndex+1] = y1;
- iIndex+=2;
- }
- return iIndex;
- }
-
- if( x1==x2 ) //是一竖线
- {
- if(y1>y2)
- {
- y=y2; y2=y1; y1=y;
- }
-
- for (j=y1;j<=y2;j++)
- {
- pData[iIndex] = x1;
- pData[iIndex+1] = j;
- iIndex+=2;
- }
- return iIndex;
- }
-
- if( abs(y2-y1) <= abs(x2-x1) )
- {
- if( (y2<y1&&x2<x1) || (y1<=y2&&x1>x2) )
- {
- x=x2; y=y2; x2=x1; y2=y1; x1=x; y1=y;
- }
-
- if( y2>=y1 && x2>=x1 )
- {
- x=x2-x1;
- y=y2-y1;
- p=2*y;
- n=2*x-2*y;
- tn=x;
-
- while(x1<=x2)
- {
- if(tn>=0)
- tn-=p;
- else
- {
- tn+=n;
- y1++;
- }
-
- pData[iIndex] = x1;
- pData[iIndex+1] = y1;
- iIndex+=2;
-
- x1++;
- }
- }
- else
- {
- x=x2-x1;
- y=y2-y1;
- p=-2*y;
- n=2*x+2*y;
- tn=x;
- while(x1<=x2)
- {
- if(tn>=0)
- tn-=p;
- else
- {
- tn+=n;
- y1--;
- }
- pData[iIndex] = x1;
- pData[iIndex+1] = y1;
- iIndex+=2;
-
- // putpixel(x1,y1);
- x1++;
- }
- }
- }
- else
- {
- x=x1; x1=y2; y2=x; y=y1; y1=x2; x2=y;
- if( (y2<y1&&x2<x1) || (y1<=y2&&x1>x2) )
- {
- x=x2; y=y2; x2=x1; y2=y1; x1=x; y1=y;
- }
-
- if( y2>=y1 && x2>=x1 )
- {
- x=x2-x1; y=y2-y1;
- p=2*y; n=2*x-2*y; tn=x;
- while(x1<=x2)
- {
- if(tn>=0)
- tn-=p;
- else
- {
- tn+=n;
- y1++;
- }
- // putpixel(y1,x1);
- pData[iIndex] = y1;
- pData[iIndex+1] = x1;
- iIndex+=2;
-
- x1++;
- }
- }
- else
- {
- x=x2-x1; y=y2-y1;
- p=-2*y; n=2*x+2*y; tn=x;
-
- while(x1<=x2)
- {
- if(tn>=0)
- tn-=p;
- else
- {
- tn+=n;
- y1--;
- }
- // putpixel(y1,x1);
- pData[iIndex] = y1;
- pData[iIndex+1] = x1;
- iIndex+=2;
-
- x1++;
- }
- }
- }
- return iIndex;
- }
- void ShowXY()
- {
- textattr(0x0f);
- gotoxy(70,1);
- cprintf("X=%u",xx);
- gotoxy(70,2);
- cprintf("Y=%u",yy);
- gotoxy(65,4);
- cprintf("Total= %lu",count);
- }
- void ClearMap()
- {
- for (int y=0;y<YSIZE;y++)
- {
- for (int x=0;x<XSIZE;x++)
- {
- Map[y][x]=0;
- }
- }
- }
- void MakeMap()
- {
- int y,x;
- int iData;
-
- ClearMap();
- randomize();
- for (y=0;y<YSIZE;y++)
- {
- for (x=0;x<XSIZE;x++)
- {
- iData = random(1000);
- if ( (iData>0) && (iData<300) )
- Map[y][x]=DIE;
- }
- }
- for (y=0;y<5;y++)
- {
- for (x=0;x<5;x++)
- {
- Map[y][x]=0;
- Map[YSIZE-y-1][XSIZE-x-1]=0;
- }
- }
- }
- void DrawBox(int x1,int y1,int x2,int y2)
- {
- textattr(0x7);
- for (int i=0;i<x2-x1;i++)
- {
- gotoxy(i+x1,y1);
- cprintf("?);
- gotoxy(i+x1,y2);
- cprintf("?);
- }
- for (i=0;i<y2-y1;i++)
- {
- gotoxy(x1,y1+i);
- cprintf("?);
- gotoxy(x2,y1+i);
- cprintf("?);
- }
-
- }
- void ShowMan()
- {
- gotoxy(oldxx+2+1,oldyy+2+1);
- textattr(14);
- cprintf(".");
-
- gotoxy(xx+2+1,yy+2+1);
- textattr(13);
- cprintf("");
- }
- void ShowMap()
- {
- int X=2,Y=2;
- DrawBox(X,Y,X+XSIZE+1,Y+YSIZE+1);
- gotoxy(X+XSIZE+1,Y+YSIZE);
- cprintf(" ");
- gotoxy(X+1,Y);
- cprintf(" ");
-
- for (int y=0;y<YSIZE;y++)
- {
- for (int x=0;x<XSIZE;x++)
- {
- gotoxy(x+X+1,y+Y+1);
- switch(Map[y][x])
- {
- case DIE:
- textattr(4);
- cprintf("?);
- break;
- case 254:
- textattr(0x2);
- cprintf("?);
- case 0:
- case 1:
- textattr(0x0f);
- cprintf(" ");
- break;
- default:
- textattr(0x0E);
- cprintf(".");
- }
-
- }
- }
- }
- int isOver()
- { //判断是否死路, 判断是不是所有走过的路周围都没有路了,如果是这样就是死路了
- int y,x;
- //看看是不是还有气
- for (y=0;y<YSIZE;y++)
- {
- for (x=0;x<XSIZE;x++)
- {
- if (Map[y][x]==0)
- continue;
-
- if (Map[y][x]==DIE)
- continue;
-
- if (y>1)
- if (Map[y-1][x]==0)
- return 0;
-
- if (y<YSIZE-1)
- if (Map[y+1][x]==0)
- return 0;
-
- if (x>1)
- if (Map[y][x-1]==0)
- return 0;
-
- if (x<XSIZE-1)
- if (Map[y][x+1]==0)
- return 0;
- }
- }
-
- return 1;
- }
- int GoToThere()
- {
- int tx,ty;
- unsigned char dd[4];
- int i,j,d;
- unsigned char min,data;
-
- for (d=0;d<4;d++)
- {
- tx = xx + dir[d][0];
- ty = yy + dir[d][1];
- if ((tx>=XSIZE)||(tx<0))
- {
- dd[d]=DIE;
- continue;
- }
- if ((ty>=YSIZE)||(ty<0))
- {
- dd[d]=DIE;
- continue;
- }
- dd[d]=Map[ty][tx];
- }
-
- data=dd[0];
- min=0;
-
- for (i=0;i<4;i++)
- {
- if (data>dd[i])
- {
- data=dd[i];
- min = i;
- }
- }
-
- return min;
- }
- int Go()
- {
- int i,d;
- count++;
- d = GoToThere();
- oldxx=xx;
- oldyy=yy;
- xx = xx + dir[d][0];
- yy = yy + dir[d][1];
- Map[oldyy][oldxx]++;
-
- if (Map[oldyy][oldxx]==1)
- Map[oldyy][oldxx] = 2;
-
- return 0;
- }
- int Success()
- {
- if ((xx>=XSIZE-1) && (yy>=YSIZE-1))
- {
- // do
- // {
- gotoxy(70,5);
- textattr(0xee);
- cprintf("SUCCESS!"); //SUCCESS!
- gotoxy(70,6);
- textattr(0xee);
- cprintf("Esc to Exit");
- // } while(getch()!=27);
- return 0;
- }
- return -1;
- }
- int isExistPosInSameAreaList(int p_iX,int p_iY)
- {
- for (int i=0;i<g_iSameAreaCount;i++)
- {
- if ( (g_SameAreaList[i][0] == p_iX) && (g_SameAreaList[i][1] == p_iY) )
- return 1;
- }
-
- return 0;
- }
- int AddOnePosToSameAreaList(int p_iX,int p_iY)
- {
- if (isExistPosInSameAreaList(p_iX,p_iY))
- return 0;
-
- g_SameAreaList[g_iSameAreaCount][0] = p_iX;
- g_SameAreaList[g_iSameAreaCount][1] = p_iY;
- g_iSameAreaCount++;
-
- return g_iSameAreaCount;
- }
- int GetSameArea(int p_iX,int p_iY)
- {
- int iNewX,iNewY;
- int iHasSame = 0;
- for (int d=0;d<4;d++)
- {
- iNewX = p_iX + dir[d][0];
- iNewY = p_iY + dir[d][1];
-
- if ( (iNewX>=0) && (iNewX<XSIZE) && (iNewY>=0) && (iNewY<YSIZE) )
- { //新的位置有效
- if (Map[iNewY][iNewX]==Map[p_iY][p_iX])
- {
- iHasSame = 1;
- if (AddOnePosToSameAreaList(iNewX,iNewY)!=0) //追加成功一个新的节点
- if (GetSameArea(iNewX,iNewY)==0)//再查询下一个节点
- return 0;
- }
- }
- }
-
- return iHasSame;
- }
- int GetSameAreaList(int x,int y)
- { //从map中得到一片相连的区域,存放到 listSameArea
- g_iSameAreaCount = 0;
- return GetSameArea(x,y);
- }
- int GetShortStepCount(int x1,int y1,int x2,int y2,int p_iStep)
- {
- int iNewX,iNewY;
- // int iStepCount = 0;
- int iTemp;
-
-
-
- for (int d=0;d<4;d++)
- {
- iNewX = x1 + dir[d][0];
- iNewY = y1 + dir[d][1];
-
- if ( (iNewX>=0) && (iNewX<XSIZE) && (iNewY>=0) && (iNewY<YSIZE) ) { //新的位置有效
- if (Map[iNewY][iNewX]==Map[x1][y1]) {
- if ((iNewX==x2) && (iNewY==y2))
- return p_iStep;
-
- iTemp = GetShortStepCount(iNewX,iNewY,XSIZE-1,YSIZE-1,p_iStep);
- if (iTemp==9999)
- Map[iNewX][iNewY] = 100;
-
- p_iStep+=iTemp;
- }
- }
- }
-
- Map[y1][x1] = 100;
- return 9999;
- }
- int GetShortPathList()
- {
- int iNewX,iNewY;
- int iIndex;
- int i,d,x,y;
-
-
- Map[0][0] = 1;
-
- while (Map[YSIZE-1][XSIZE-1]==0) {
- for (y=0;y<YSIZE;y++)
- {
- for (x=0;x<XSIZE;x++)
- {
- if (Map[y][x]==DIE)
- continue;
-
- if (Map[y][x]==0)
- continue;
-
- for (d=0;d<4;d++)
- {
- iNewX = x + dir[d][0];
- iNewY = y + dir[d][1];
- if ( (iNewX>=0) && (iNewX<XSIZE) && (iNewY>=0) && (iNewY<YSIZE) ) { //新的位置有效
- if (Map[iNewY][iNewX]==DIE)
- continue;
-
- if (Map[iNewY][iNewX]==0)
- Map[iNewY][iNewX] = Map[y][x] + 1;
- else if (Map[iNewY][iNewX]>(Map[y][x] + 1))
- Map[iNewY][iNewX] = Map[y][x] + 1;
- }
- }
- }
- }
- }
-
- iIndex = 0;
-
- iIndex = 0;
- x = XSIZE-1;
- y = YSIZE-1;
- g_ShortPathList[iIndex][0] = x;
- g_ShortPathList[iIndex][1] = y;
- iIndex++;
- while(1) {
- if ( (x==0) && (y==0) )
- break;
-
- for (d=0;d<4;d++)
- {
- iNewX = x + dir[d][0];
- iNewY = y + dir[d][1];
- if ( (iNewX>=0) && (iNewX<XSIZE) && (iNewY>=0) && (iNewY<YSIZE) ) { //新的位置有效
- if (Map[iNewY][iNewX]==(Map[y][x]-1)) {
- g_ShortPathList[iIndex][0] = iNewX;
- g_ShortPathList[iIndex][1] = iNewY;
- iIndex++;
- x = iNewX;
- y = iNewY;
- break;
- }
- }
- }
- }
-
- g_iShortPathCount = iIndex;
- return g_iShortPathCount;
- }
- void ShowSameArea()
- {
- for (int i=0;i<g_iSameAreaCount;i++)
- {
- Map[g_SameAreaList[i][1]][g_SameAreaList[i][0]] = 10;
- }
-
- ShowMap();
- }
- int GetPathCount(int p_iX,int p_iY)
- {//得到一个节点的通路个数
- int iNewX,iNewY;
- int iPathCount = 0;
- for (int d=0;d<4;d++)
- {
- iNewX = p_iX + dir[d][0];
- iNewY = p_iY + dir[d][1];
-
- if ( (iNewX>=0) && (iNewX<XSIZE) && (iNewY>=0) && (iNewY<YSIZE) ) { //新的位置有效
- if (Map[iNewY][iNewX]==1)
- iPathCount++;
- else if (Map[iNewY][iNewX]==0)
- iPathCount++;
- }
- }
- return iPathCount;
- }
- int DropAllLeaf()
- {
- int iCount;
-
- //删除单一叶子结点
- do {
- iCount = 0;
-
- for (int i=0;i<g_iSameAreaCount;i++)
- {
- if (GetPathCount(g_SameAreaList[i][0],g_SameAreaList[i][1])<=1)
- {
- Map[g_SameAreaList[i][1]][g_SameAreaList[i][0]] = 254;
- g_SameAreaList[i][0] = 0;
- g_SameAreaList[i][1] = 0;
- iCount++;
- }
- }
- } while(iCount>0);
-
- return iCount;
- //删除两个分支的结点
- }
- int DropDoubleLeaf()
- {
- int SameAreaList[YSIZE*XSIZE][2]; //相同区域的列表
- // int iSameAreaCount = 0;
- for (int i=0;i<g_iSameAreaCount;i++)
- {
- memcpy((char *)SameAreaList,g_SameAreaList,YSIZE*XSIZE*2*sizeof(int));
- // iSameAreaCount = g_iSameAreaCount;
- if (GetPathCount(g_SameAreaList[i][0],g_SameAreaList[i][1])==2)
- { //有两条分支
- Map[g_SameAreaList[i][1]][g_SameAreaList[i][0]] = 254;
- g_SameAreaList[i][0] = 0;
- g_SameAreaList[i][1] = 0;
- // iCount++;
- }
- }
- return 0;
- }
- void init()
- {
- xx=0,yy=0;
- oldxx=xx,oldyy=yy;
- count = 0;
-
-
- // highvideo(void);
- // lowvideo(void);
- // normvideo(void);
- clrscr();
- clrscr();
- _setcursortype(_NOCURSOR);
- }
- void end()
- {
- // highvideo(void);
- // lowvideo(void);
- // normvideo(void);
-
- textattr(0x07);
- clrscr();
- _setcursortype(_NORMALCURSOR);
- }
- void main()
- {
- int i;
- // highvideo();
- textmode(64);
-
- end();
- init();
-
- lab_begin:
-
-
- end();
- init();
- MakeMap();
-
- GetSameAreaList(1,1);
-
- if (!isExistPosInSameAreaList(XSIZE-1,YSIZE-1)) {
- gotoxy(70,5);
- textattr(0xee);
- cprintf("disconnect!");
- gotoxy(70,6);
- textattr(0xee);
- cprintf("Esc to Exit");
- sound(500);
- delay(100);
- sound(250);
- delay(100);
- sound(500);
- delay(100);
- nosound();
-
- ShowSameArea();
- // ShowMap();
- // getch();
- delay(1000);
-
- goto lab_begin;
- }
-
- // ShowSameArea();
-
- for (i=0;i<g_iSameAreaCount;i++)
- Map[g_SameAreaList[i][1]][g_SameAreaList[i][0]] = 0;
- /*
- g_iShortPathCount = LineDDA(0,0,XSIZE-1,YSIZE-1,g_ShortPathList); // 最段的路径点列表
- printf("\n%d\n",g_iShortPathCount);
- */
-
- g_iShortPathCount = 0 ;
- GetShortPathList();
-
- for (i=0;i<g_iSameAreaCount;i++)
- Map[g_SameAreaList[i][1]][g_SameAreaList[i][0]] = 1;
-
- for (i=0;i<g_iShortPathCount;i++) {
- if (Map[g_ShortPathList[i][1]][g_ShortPathList[i][0]]!=DIE)
- Map[g_ShortPathList[i][1]][g_ShortPathList[i][0]] = 0;
- }
-
- /*
- g_iShortPathCount = 0 ;
- // GetShortPathList();
- g_iShortPathCount = LineDDA(0,0,XSIZE-1,YSIZE-1,g_ShortPathList); // 最段的路径点列表
- for (i=0;i<g_iShortPathCount;i++) {
- if (Map[g_ShortPathList[i][1]][g_ShortPathList[i][0]]!=DIE)
- Map[g_ShortPathList[i][1]][g_ShortPathList[i][0]] = 0;
- }
- */
- // delay(2000);
- ShowMap();
-
- do
- {
- Go();
-
- //ShowMap();
- ShowMan();
- ShowXY();
-
- if (Success()==0)
- {
- delay(1000);
- end();
- goto lab_begin;
- // return;
- }
-
- delay(50);
-
- }while(!kbhit());
- if (getch()!=27)
- goto lab_begin;
-
- _setcursortype(_NORMALCURSOR);
- clrscr();
- // normvideo();
- textmode(-1);
- }
- /*
- 20:05 2005-9-9
- 今天是周末,没很多事,抽空研究了一下搜索算法.因为前几天去论坛看到有网友请教迷宫算法的问题,我把很久以前写的
- 一个走迷宫的程序贴上去了.这个程序比较土,不会判断随机产生的迷宫是否能走通,不是按最短路径搜索,但是,只要是
- 能连通的迷宫就肯定能走出去.呵呵,我的算法没学好,很多时候就搞自已瞎琢磨了.
- 以前的程序算法是这样的:
-
- 1.随机产生由0x00和0xff结成的地图
- 2.从(0,0)点开始进入迷宫
- 3.因为出口在(MAXX,MAXY),所以搜索方向是 右->下->上->左
- 4.每走过一个方格把此方格对应的值加1
- 5.在选择方向时,总是优先选择方格值最小的相邻方格,这样,一个方格走过的次数越多就越不会再次走入,
- 所以自然而然就会走到(MAXX,MAXY)了
- 这种算法导致"小人"会在迷宫里不停的走来走去,很多时候是在重复走动,看起来傻傻的(俺喜欢)
- 为了解决判断迷宫是否能走通问题,和求最短路径问题,我想了很久.
- 嫌型阉悼梢杂肁*算法来探路比较好,我去找了几篇资料,没看太懂,
- 自已瞎折腾一通,又搞出一个新算法,也不知道学名叫什么,反正结果看起来是对的.呵呵
- 新的算法是这样的:
- 1.随机产生由0x00和0xff结成的地图
- 2.建立一个空的"连通地图方格列表",然后用递归方法去搜索所有与(0,0)相同值的方格,然后把坐格存入"连通地图方格列表"中
- 在递归时,如果碰到"连通地图方格列表"中已经存在的方格则跳出.这样,就产生了一个"连通地图方格列表",然后只要
- 判断迷宫入口坐标(0,0)和出口坐标(MAXX,MAXY)是否都在列表时就可以知道是否迷宫能走通了,好简单吧:)
- 3.把迷宫入口坐标(0,0)的赋值为1,然后用双重循环判断迷宫中每一方格,如果一个方格的值>1且小于255的话,则把相邻
- 的方格值全部加1,如果某一个相邻方格的值比所在方格值+1还要大的话(因为连通的原因),则把相邻方格设成方格值+1
- 重复这样做,直到 出口坐标(MAXX,MAXY) 也被赋值为止.
- 4.现在工作就很简单了,从出口坐标(MAXX,MAXY)开始向上推,逐次递减直到入口坐标(0,0),这样就得到了一个由多个
- 坐标组成的路线表,也就是最短路径了(看起来是的)
- 5.因为是在老的程序基础上改的,也没有仔细弄,把最短路径经过方格全部设为0,把其它连通的方格则全部设为1,
- 这样老的程序不做什么修改就OK了.
- 6.欣赏了几十遍小人走通迷宫的路线,直是简洁,呵呵.
- 嗯,程序虽然表面上功能是实现了,但不知道这样处理是不是会有漏洞.
-
- 算法书上的公式都看不懂,郁闷.
- */
复制代码
|