简单迷宫
首先,因为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;
}