简简单单小迷宫——随机迷宫+最短路径

简单迷宫

首先,因为C++中没有TC所特有的gotoxy()函数,所以要先自己写一个函数,实现gotoxy()函数输出文本里面光标定位的功能。

其次,按照随机普里姆算法的思想,构建了一个随机迷宫,特点是迷宫全局只有一条通路。

然后,运用递归与队列寻找迷宫的可行路径,可以找到该迷宫的最短路径。(然而我这个随机迷宫只有一条路径,可行即最短)

最后,依靠gotoxy()稍稍优化一下用户界面。

.------------------------------------------------------------------------------------------------------------------------.

这样一来就大功告成,打完收工了

下面是代码

#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
using namespace std;
#define  WRONG  -1
#define INIT_QUEUE_SIZE 15000
/*光标的初始坐标为(0,0),任一坐标(x,y)中,x表示第几列,y表示第几行*/
/*东1,南2,西3,北4*/

/*可行方块数据结构*/
typedef struct Box{
	char elem;/*方块状态*/
	char mark;/*识别标记*/ 
}Box; 

/*墙壁数组单位数据结构*/
typedef struct Wall{
	int col,row;
	struct Wall* next;
}Wall,Head;

/*队列单位存储单元*/
typedef struct QueueElem{
	int r,c;
	int steps;
	int towards;
}QueueElem;

/*队列数据结构*/
typedef struct Queue{
	QueueElem* front;
	QueueElem* rear;
	int queuelen;
}Queue; 


/*----光标定位----*/ 
void gotoxy(int x,int y)
{
    COORD pos;
	 pos.X=x;
	 pos.Y=y;                                  
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);   
}
void getxy(int &x,int &y)
{ 
	HANDLE hStdout;
	CONSOLE_SCREEN_BUFFER_INFO pBuffer; 
	hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
	GetConsoleScreenBufferInfo(hStdout, &pBuffer);
	x=pBuffer.dwCursorPosition.X;
	y=pBuffer.dwCursorPosition.Y;
}


/*----动态链表----*/
void Link_MallocLinked(Head* &head,int r,int c)/*结点分配*/
{
	Wall* p;

	if(head==NULL){
		head=(Head*)malloc(sizeof(Head));
		if(!head) exit(WRONG);
		head->col=0;
		head->next=NULL;
	}
	else{
		p=(Wall*)malloc(sizeof(Wall));
		if(!p) exit(WRONG);
		p->col=c;p->row=r;
		p->next=head->next;
		head->next=p;
		(head->col)+=1;
	}

	return;
}
void Link_RemoveDelete(Head* &head,Wall* &p)/*结点释放*/
{
	Wall* pt;
	if(head==NULL) return;
	if(head->next==NULL){
		free(head);
		head=NULL;
	}
	else{
		pt=p->next;
		p->next=pt->next;
		free(pt);
		(head->col)-=1;
	} 

	return;
}
Wall* Link_Travel(Head* head,int randnum)/*依位序遍历*/
{
	/*寻找链表中次序为randnum的结点的直接前驱*/
	int i;
	Wall* p=head;

	for(i=1;i<randnum;i++)
		p=p->next;

	return p; 
}


/*----动态队列----*/
void Queue_InitQueue(Queue* &Q)
{
	if(Q!=NULL) return;
	Q=(Queue*)malloc(sizeof(Queue));
	if(!Q) exit(WRONG);
	Q->front=(QueueElem*)malloc(sizeof(QueueElem)*INIT_QUEUE_SIZE);
	if(!Q->front) exit(WRONG);
	Q->rear=Q->front;
	Q->queuelen=0;

	return;
} 
void Queue_EnQueue(Queue* Q,int r,int c,int steps,int towards)
{
	if(Q->queuelen+1>INIT_QUEUE_SIZE) exit(WRONG);
	Q->rear->r=r;
	Q->rear->c=c;
	Q->rear->steps=steps;
	Q->rear->towards=towards;
	Q->rear++;
	Q->queuelen++;

	return;
}
void Queue_Rear_DeQueue(Queue* Q)
{
	if(Q->queuelen<=0) exit(WRONG);
	Q->queuelen--;
	Q->rear--;
}
void Queue_CpyQueue(Queue* Q,Queue* P)
{
	/*将队列Q的内容全部复制到队列S中,假设队头无移动*/
	QueueElem* pt=Q->front;

	P->rear=P->front;
	P->queuelen=0;
	while(pt!=Q->rear){
		*(P->rear)=*pt;
		P->rear++;pt++;
	}
	P->queuelen=Q->queuelen;/*队长改变*/

	return;
} 


/*----迷宫路径----*/
void Path_Output(Box** CMap,int r,int c,int gotox,int gotoy)
{
	int i,j;

	for(i=0;i<r;i++)
	{
		gotoxy(gotox,gotoy+i);
		for(j=0;j<c;j++)
		{
			if(CMap[i][j].elem=='*') cout<<' ';
			else cout<<CMap[i][j].elem;
		}
	}
}
void Path_CpyPath(Queue* &Q,Queue* &P)
{
	QueueElem *ptQ,*ptP;

	if(P->queuelen<=0){
		Queue_CpyQueue(Q,P);
		return;
	} 
	ptQ=Q->rear-1;
	ptP=P->rear-1;
	if(ptQ->steps<ptP->steps)
		Queue_CpyQueue(Q,P);

	return;
}
void Path_CreatMaze(Box** Map,Box** &CMap,Box* &cmap,int ro,int co)
{
	int i,j;

	CMap=(Box**)malloc(sizeof(Box*)*ro);
	cmap=(Box*)malloc(sizeof(Box)*(ro*co));
	if(!CMap||!cmap) exit(WRONG);

	for(i=0;i<ro;i++)
		CMap[i]=&cmap[i*co];

	for(i=0;i<ro;i++)
		for(j=0;j<co;j++){
			CMap[i][j].elem=Map[i][j].elem;
			CMap[i][j].mark=Map[i][j].mark;
		}

	return;
} 
void Path_CalcuPath(Box** &CMap,Queue* &Q,Queue* &P,int ro,int co,int cols,int lines)/*递归求最短路径*/
{
	int i=0;
	QueueElem* pQ=Q->rear-1;
	int cro=pQ->r,cco=pQ->c;

	CMap[cro][cco].elem='*';

	if(cro==ro-2&&cco==co-2){
		/*找到迷宫出口*/
		CMap[cro][cco].elem=' ';/*擦掉地图染色*/
		Path_CpyPath(Q,P);/*保存路径*/
		Queue_Rear_DeQueue(Q);
		return;
	}

	if(CMap[cro][cco+1].elem==' '){/*东方*/
		i++;
		Queue_EnQueue(Q,cro,cco+1,pQ->steps+1,1);
		Path_CalcuPath(CMap,Q,P,ro,co,cols,lines); 
	}
	if(CMap[cro+1][cco].elem==' '){/*南方*/
		i++;
		Queue_EnQueue(Q,cro+1,cco,pQ->steps+1,2);
		Path_CalcuPath(CMap,Q,P,ro,co,cols,lines); 
	}
	if(CMap[cro][cco-1].elem==' '){/*西方*/
		i++;
		Queue_EnQueue(Q,cro,cco-1,pQ->steps+1,3);
		Path_CalcuPath(CMap,Q,P,ro,co,cols,lines); 
	}
	if(CMap[cro-1][cco].elem==' '){/*北方*/
		i++;
		Queue_EnQueue(Q,cro-1,cco,pQ->steps+1,4);
		Path_CalcuPath(CMap,Q,P,ro,co,cols,lines); 
	}

	if(CMap[cro][cco+1].elem!=' '&&CMap[cro-1][cco].elem!=' '&&CMap[cro][cco-1].elem!=' '&&CMap[cro+1][cco].elem!=' ')
	{
		if((cro==1&&cco==2)||(cro==2&&cco==1)){
			/*循环回到起点*/
			CMap[cro][cco].elem=' ';
			Queue_Rear_DeQueue(Q);
			return; 
		}
		else{
			/*遇到死胡同,未找到迷宫出口,则不涂去地图中死胡同的染色*/ 
			Queue_Rear_DeQueue(Q);
			return; 
		}
	}

	/*正常探索完一条通路的其中一个'路口'*/ 
	CMap[cro][cco].elem=' ';/*涂去地图中的染色*/ 
	Queue_Rear_DeQueue(Q);
	return;
}

/*----迷宫地图----*/
void Map_Output(Box** Map,int r,int c,int gotox,int gotoy)
{
	int i,j;

	for(i=0;i<r;i++)
	{
		gotoxy(gotox,gotoy+i);
		for(j=0;j<c;j++)
			cout<<Map[i][j].elem;
	}
}
void Map_MazeSize(Box** &Map,Box* &map,int ro,int co)/*初始化迷宫地图*/
{
	int i,j;

	/*字符数组,字符指针数组分配空间*/
	Map=(Box**)malloc(ro*sizeof(Box*));
	map=(Box*)malloc((co*ro)*sizeof(Box));
	if(!Map||!map) exit(WRONG);

	/*字符指针数组与字符数组产生联系*/ 
	for(i=0;i<ro;i++)
		Map[i]=&map[i*co];

	/*构建初始化地图*/
	for(i=0;i<ro;i++)
		for(j=0;j<co;j++)
		{
			Map[i][j].mark='0';
			if(i%2==1&&j%2==1) Map[i][j].elem=' ';
			else if(i!=0&&i!=(ro-1)&&j!=0&&j!=(co-1))	Map[i][j].elem='#';
			else{
				Map[i][j].elem='#';
				Map[i][j].mark='1';
			}
		}

	return;
}
char Map_Towards(Head* head,Wall* pt,Box** Map)
{
	/*判断上下左右四个方向是否含有新可行方块,'n','s','w','e',以及无方向'o'*/
	int r=pt->row,c=pt->col;
	Wall *p;

	Map[r][c].elem=' ';
	if(Map[r][c+1].elem==' '&&Map[r][c+1].mark=='0'&&Map[r][c-1].elem==' '&&Map[r][c-1].mark=='1')	return 'e';
	else if(Map[r][c-1].elem==' '&&Map[r][c-1].mark=='0'&&Map[r][c+1].elem==' '&&Map[r][c+1].mark=='1')	return 'w';
	else if(Map[r+1][c].elem==' '&&Map[r+1][c].mark=='0'&&Map[r-1][c].elem==' '&&Map[r-1][c].mark=='1')	return 's';
	else if(Map[r-1][c].elem==' '&&Map[r-1][c].mark=='0'&&Map[r+1][c].elem==' '&&Map[r+1][c].mark=='1')	return 'n';
	else {
		Map[r][c].elem='#';
		return 'o';
	}
}
void Map_EnLinkList(Head* head,int r,int c,Box** Map)
{
	Map[r][c].mark='1';
	if(Map[r][c+1].elem=='#'&&Map[r][c+1].mark=='0'){
		Link_MallocLinked(head,r,c+1);Map[r][c+1].mark='1';
	}
	if(Map[r][c-1].elem=='#'&&Map[r][c-1].mark=='0'){
		Link_MallocLinked(head,r,c-1);Map[r][c-1].mark='1';
	}
	if(Map[r+1][c].elem=='#'&&Map[r+1][c].mark=='0'){
		Link_MallocLinked(head,r+1,c);Map[r+1][c].mark='1';
	}
	if(Map[r-1][c].elem=='#'&&Map[r-1][c].mark=='0'){
		Link_MallocLinked(head,r-1,c);Map[r-1][c].mark='1';
	}

	return;
}
void RandomizedPrim(Box** Map)/*----随机普里姆思想----*/ 
{
	Head* head=NULL;
	Wall *p,*pt;
	int lc=1,lr=1,randnum,r,c,i,j;
	char ch; 

	Link_MallocLinked(head,0,0);/*墙壁链表头结点*/ 
	srand(time(0));/*随机值发生器*/
	Map_EnLinkList(head,1,1,Map);

	while(head->col!=0)
	{
		randnum=rand()%(head->col)+1;
		p=Link_Travel(head,randnum);/*目标结点直接前驱*/
		pt=p->next;/*目标结点*/
		r=pt->row;c=pt->col;

		ch=Map_Towards(head,pt,Map);
		Link_RemoveDelete(head,p);
		if(ch!='o'){
			switch(ch)
			{
				case 'e':Map_EnLinkList(head,r,c+1,Map);break;
				case 's':Map_EnLinkList(head,r+1,c,Map);break;
				case 'w':Map_EnLinkList(head,r,c-1,Map);break;
				case 'n':Map_EnLinkList(head,r-1,c,Map);break;
			}
		}
	}

	return;
}


/*----输出图像----*/
void Print_MazePath(Box** Map,int ro,int co,int cols,int lines)
{
	Box **CMap,*cmap;
	Queue *Q=NULL,*P=NULL;
	QueueElem* pt;
	int cro,cco,n,zx=(cols-co)/2,zy=(51-ro)/2+4,k=0;
 
	Queue_InitQueue(Q);
	Queue_InitQueue(P);

	Queue_EnQueue(Q,1,1,1,0);
	Path_CreatMaze(Map,CMap,cmap,ro,co);
	Path_CalcuPath(CMap,Q,P,ro,co,cols,lines);

	pt=P->front;
	while(pt!=P->rear)
	{
		cro=pt->r;cco=pt->c;
		CMap[cro][cco].elem='0';
		pt++;
	}

	system("cls");
	gotoxy(cols/2,1);cout<<"简单迷宫";
	gotoxy(0,2);for(n=0;n<cols;n++) cout<<"=";

	Path_Output(CMap,ro,co,zx,zy);

	gotoxy(0,56);for(n=0;n<cols;n++) cout<<"=";
	gotoxy(cols-50,57);cout<<"1.帮助(键盘按键'i':上  'm':下  'j':左  'l':右)";
	gotoxy(cols-50,58);cout<<"2.退出";
	gotoxy(0,57);cout<<"请选择方向::";

	return;
}
void Print_MainMenu()
{
	system ("cls");
	gotoxy(119,5);cout<<"主菜单";
	gotoxy(113,6);cout<<"==================";
	gotoxy(117,7);cout<<"1.难度选择";
	gotoxy(117,8);cout<<"2.退出游戏";
	gotoxy(113,9);cout<<"==================";
	gotoxy(113,11);cout<<"请选择::";
}
void Print_SelectDifficulty()
{
	system ("cls");
	gotoxy(117,5);cout<<"难度选择";
	gotoxy(113,6);cout<<"================";
	gotoxy(115,7);cout<<"1.超级迷宫";
	gotoxy(115,8);cout<<"2.高级迷宫";
	gotoxy(115,9);cout<<"3.中级迷宫";
	gotoxy(115,10);cout<<"4.低级迷宫";
	gotoxy(115,11);cout<<"5.返    回";
	gotoxy(113,12);cout<<"================";
	gotoxy(113,13);cout<<"请选择::";
}
void Print_Cursor(int &cx,int &cy,int cxt,int cyt)
{
	gotoxy(cx,cy);cout<<' ';
	cx=cxt;cy=cyt;
	gotoxy(cx,cy);cout<<'@'; 
	gotoxy(12,57);cout<<"       ";
	gotoxy(12,57);
}
void Print_Maze(int ro,int co,int cols,int lines)/*游戏界面功能闭包*/
{
	Box **Map,*map;
	int n,zx=(cols-co)/2,zy=(51-ro)/2+4,cx=zx+1,cy=zy+1;
	char ch='4',chover[10];

	Map_MazeSize(Map,map,ro,co);
	RandomizedPrim(Map);
loop:
	system ("cls");
	gotoxy(cols/2,1);cout<<"简单迷宫";
	gotoxy(0,2);for(n=0;n<cols;n++) cout<<"=";

	Map_Output(Map,ro,co,zx,zy);

	gotoxy(cx,cy);cout<<'@';
	gotoxy(0,56);for(n=0;n<cols;n++) cout<<"=";
	gotoxy(cols-50,57);cout<<"1.帮助(键盘按键'i':上  'm':下  'j':左  'l':右)";
	gotoxy(cols-50,58);cout<<"2.退出";
	gotoxy(0,57);cout<<"请选择方向::";

	while(ch!='2')
	{
		ch=getchar();gets(chover);
		switch(ch)
		{
			case 'l':if(Map[cy-zy][cx+1-zx].elem==' ') Print_Cursor(cx,cy,cx+1,cy);break;
			case 'm':if(Map[cy+1-zy][cx-zx].elem==' ') Print_Cursor(cx,cy,cx,cy+1);break;
			case 'j':if(Map[cy-zy][cx-1-zx].elem==' ') Print_Cursor(cx,cy,cx-1,cy);break;
			case 'i':if(Map[cy-1-zy][cx-zx].elem==' ') Print_Cursor(cx,cy,cx,cy-1);break;
			case '1':{Print_MazePath(Map,ro,co,cols,lines);getchar();goto loop;}break;
			case '2':ch='2';break;
			default:Print_Cursor(cx,cy,cx,cy);break;
		}
	}

	return;
}


int main(void)
{
	char ch='3',chover[10];
	int cols=240,lines=63;

	system("mode con:cols=240 lines=63");

	while(ch!='2')
	{
		Print_MainMenu();
		ch=getchar();gets(chover);

		if(ch=='1'){
			while(ch!='5')
			{
				Print_SelectDifficulty();
				ch=getchar();getchar();
				switch(ch)
				{
					case '1':Print_Maze(51,229,cols,lines);break;
					case '2':Print_Maze(41,179,cols,lines);break;
					case '3':Print_Maze(31,129,cols,lines);break;
					case '4':Print_Maze(21,79,cols,lines);break;
				}
			}
		}
	}

	return 0;
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值