C语言之180行随机迷宫代码详解与分析之整理版.docx
《C语言之180行随机迷宫代码详解与分析之整理版.docx》由会员分享,可在线阅读,更多相关《C语言之180行随机迷宫代码详解与分析之整理版.docx(20页珍藏版)》请在冰豆网上搜索。
C语言之180行随机迷宫代码详解与分析之整理版
C语言之180行“随机迷宫”代码详解与分析之整理版
代码如下:
*迷宫游戏byCDQ*/
/*
vc++6.0编译成功
本程序参照网上一个特殊算法随机生成迷宫
该算法优点:
效率高,从入口到出口只有唯一路径,入口出口自己设定
该算法缺点:
宽度高度都必须为奇数,只能生成n*m矩阵迷宫
*/
#include
#include
#include
#include
#defineHeight31//迷宫的高度,必须为奇数
#defineWidth25//迷宫的宽度,必须为奇数
#defineWall1
#defineRoad0
#defineStart2
#defineEnd3
#defineEsc5
#defineUp1
#defineDown2
#defineLeft3
#defineRight4
intmap[Height+2][Width+2];
voidgotoxy(intx,inty)//移动坐标
{
COORDcoord;
coord.X=x;
coord.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
}
voidhidden()//隐藏光标
{
HANDLEhOut=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFOcci;
GetConsoleCursorInfo(hOut,&cci);
cci.bVisible=0;//赋1为显示,赋0为隐藏
SetConsoleCursorInfo(hOut,&cci);
}
voidcreate(intx,inty)//随机生成迷宫
{
intc[4][2]={0,1,1,0,0,-1,-1,0};//四个方向
inti,j,t;
//将方向打乱
for(i=0;i<4;i++)
{
j=rand()%4;
t=c[i][0];c[i][0]=c[j][0];c[j][0]=t;
t=c[i][1];c[i][1]=c[j][1];c[j][1]=t;
}
map[x][y]=Road;
for(i=0;i<4;i++)
if(map[x+2*c[i][0]][y+2*c[i][1]]==Wall)
{
map[x+c[i][0]][y+c[i][1]]=Road;
create(x+2*c[i][0],y+2*c[i][1]);
}
}
intget_key()//接收按键
{
charc;
while(c=getch())
{
if(c==27)returnEsc;//Esc
if(c!
=-32)continue;
c=getch();
if(c==72)returnUp;//上
if(c==80)returnDown;//下
if(c==75)returnLeft;//左
if(c==77)returnRight;//右
}
return0;
}
voidpaint(intx,inty)//画迷宫
{
gotoxy(2*y-2,x-1);
switch(map[x][y])
{
caseStart:
printf("入");break;//画入口
caseEnd:
printf("出");break;//画出口
caseWall:
printf("※");break;//画墙
caseRoad:
printf("");break;//画路
}
}
voidgame()
{
intx=2,y=1;//玩家当前位置,刚开始在入口处
intc;//用来接收按键
while
(1)
{
gotoxy(2*y-2,x-1);
printf("☆");//画出玩家当前位置
if(map[x][y]==End)//判断是否到达出口
{
gotoxy(30,24);
printf("到达终点,按任意键结束");
getch();
break;
}
c=get_key();
if(c==Esc)
{
gotoxy(0,24);
break;
}
switch(c)
{
caseUp:
//向上走
if(map[x-1][y]!
=Wall)
{
paint(x,y);
x--;
}
break;
caseDown:
//向下走
if(map[x+1][y]!
=Wall)
{
paint(x,y);
x++;
}
break;
caseLeft:
//向左走
if(map[x][y-1]!
=Wall)
{
paint(x,y);
y--;
}
break;
caseRight:
//向右走
if(map[x][y+1]!
=Wall)
{
paint(x,y);
y++;
}
break;
}
}
}
intmain()
{
inti,j;
srand((unsigned)time(NULL));//初始化随即种子
hidden();//隐藏光标
for(i=0;i<=Height+1;i++)
for(j=0;j<=Width+1;j++)
if(i==0||i==Height+1||j==0||j==Width+1)//初始化迷宫
map[i][j]=Road;
elsemap[i][j]=Wall;
create(2*(rand()%(Height/2)+1),2*(rand()%(Width/2)+1));//从随机一个点开始生成迷宫,该点行列都为偶数
for(i=0;i<=Height+1;i++)//边界处理
{
map[i][0]=Wall;
map[i][Width+1]=Wall;
}
for(j=0;j<=Width+1;j++)//边界处理
{
map[0][j]=Wall;
map[Height+1][j]=Wall;
}
map[2][1]=Start;//给定入口
map[Height-1][Width]=End;//给定出口
for(i=1;i<=Height;i++)
for(j=1;j<=Width;j++)//画出迷宫
paint(i,j);
game();//开始游戏
getch();
return0;
}
分析如下:
首先,先挂上代码。
然后说部分废话,读代码好处非常之多,提高技术,增加理解力,以及获得不同思路等。
读代码甚至对比写代码来说,学习效率有过之而无不及.文章针对初级又在初级之上,没有一定的基础看不懂,有一定的基础就可以跟着这篇帖子,做出你自己的C语言随机迷宫,这里的做出并不是抄代码,而是变为你真正的知识,在没有参考的时候,也可以流畅的写出你的代码.
然后我们开始分析代码..
先看头文件。
#include//包涵标准输入输出函数
#include//控制台输入输出库,非标准库哦
#include//WINDOWS.H是主要的头文件,它包含了其他Windows头文件,这些头文件的某些也包含了其他头文件。
具体包涵了什么。
。
太多了自行XX
#include//包涵时间和日期处理函数
#defineHeight21//迷宫的高度,必须为奇数
#defineWidth21//迷宫的宽度,必须为奇数
#defineWall1//即字面意思墙
#defineRoad0//即字面意思路
#defineStart2//入口
#defineEnd3//终点
#defineEsc5//退出
#defineUp1//上,下,左,右
#defineDown2
#defineLeft3
#defineRight4
这里为什么要用宏,什么情况下使用宏,可能要问为什么不直接用12345来代替。
简单的来说就是提供一个方便,并增加一定的效率。
还有重要的一点就是增加代码的可读性。
尽量避免用01234这样无意义的数字而使用宏定义能良好的提高开发效率,在小程序中可能不算什么,但是在大程序可就不一样了,然而宏定义也并非只能定义简单的1234。
接下来我们看一共有几个函数
voidgotoxy(intx,inty)//既字面含义移动坐标
voidcreate(intx,inty)//字面含义创建迷宫
voidhidden()//隐藏光标(注并非鼠标)
intget_key()//得到按键
voidpaint(intx,inty)//绘制迷宫
voidgame()//游戏相关操作
先不要管main函数里的代码,我们先逐个分析一下函数
先来看看gotoxy()接受两个参数,代码如下
voidgotoxy(intx,inty)//移动坐标
{
COORDcoord;
coord.X=x;
coord.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
}
看到这里可能就有很多人蒙了COORD是个什么东西?
COORD实际上是一个结构体包括结构体成员SHORTX,SHORTY;
typedefstructCOORD{SHORTX;SHORTY;}COORD,*PCOORD;暂时先不管他是做什么的,先看看SetConsoleCursorPosition这个API的声明他接受两个参数,作用是定位光标位置,需要配合COORD使用
BOOLWINAPISetConsoleCursorPosition(__inHANDLEhConsoleOutput,//句柄就不介绍了__inCOORDdwCursorPosition//COORD原来是SetConsoleCursorPosition的形参之一);
GetStdHandle声明如下:
HANDLEWINAPIGetStdHandle(//获得输入、输出/错误的屏幕缓冲区的句柄。
__inDWORDnStdHandle);
而其参数nStdHandle的值可以为下面几种类型的一种:
STD_INPUT_HANDLE标准输入的句柄 STD_OUTPUT_HANDLE标准输出的句柄 STD_ERROR_HANDLE标准错误的句柄
这么说出来其实也并非很容易理解,我们用一个小程序来举例
#include
#include
intmain(void)
{
COORDcod;
cod.X=5;
cod.Y=4;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),cod);
}
编译一下程序,就能理解这两个函数是做什么的了
gotoxy()就讲到这里
下面讲第二个函数
声明:
voidcreate(intx,inty)
voidcreate(intx,inty)//随机生成迷宫
{
intc[4][2]={0,1,1,0,0,-1,-1,0};//四个方向//这里的四个方向乃是0,11,00,-1-1,0代表着上下左右
inti,j,t;
//将方向打乱
for(i=0;i<4;i++)
{
j=rand()%4;
t=c[0];c[0]=c[j][0];c[j][0]=t;
t=c[1];c[1]=c[j][1];c[j][1]=t;
}
map[x][y]=Road;
for(i=0;i<4;i++)
if(map[x+2*c[0]][y+2*c[1]]==Wall)//
{
map[x+c[0]][y+c[1]]=Road;
create(x+2*c[0],y+2*c[1]);
}
}
这个函数中的算法根据源代码作者所说是从网上找的.然后搜了搜.我去略长,略长,转到论坛压力略大略大还分别有不会离散数学的和使用深度优先遍历..两种版本,最主要的是带图了,推荐亲自前去观看吧,带上图理解比较容易..所以想要理解算法部分,还是看连接文章吧
然后我们接着说一下intget_key()
函数如下:
intget_key()//接收按键
{
charc;
while(c=getch())
{
if(c==27)returnEsc;//Esc
if(c!
=-32)continue;
c=getch();
if(c==72)returnUp;//上
if(c==80)returnDown;//下
if(c==75)returnLeft;//左
if(c==77)returnRight;//右
}
return0;
}
其实理解这个函数很容易getch()为无回显获取一个字符,什么叫无回显获取一个字符?
写一个小程序来测试一下
#include
#include
intmain()
{
chara;
a=getch();
putch(a);
}
可以发现只会进行输出,而输入时不会显示所输入字符。
可能会有人疑惑ESC的ASCII确实是27可是其他的是什么呀?
ASCII中是没有上下左右的值的,这里的值是键盘控制码,不是ASCII!
注意了!
关于获取某个按键的值可以用以下程序
#include
#include
intmain()
{
intkey;
key=getch();
while(key!
=27)//键入值不为ESC
{
printf("%d\n",key);
key=getch();
}
}
继续看看paint函数
函数如下
voidpaint(intx,inty)//画迷宫
{
gotoxy(2*y-2,x-1);
switch(map[x][y])
{
caseStart:
printf("入");break;//画入口
caseEnd:
printf("出");break;//画出口
caseWall:
printf("※");break;//画墙
caseRoad:
printf("");break;//画路
}
}
这个函数实际上比较容易理解,他首先将光标指向入口,然后在main函数中遍历整个map数组,画出地图。
也可以不用入出※空格这些来做地图比如改一下
switch(map[x][y])
{
caseStart:
printf("1");break;//画入口
caseEnd:
printf("2");break;//画出口
caseWall:
printf("3");break;//画墙
caseRoad:
printf("4");break;//画路
}
然后就应该能理解了这部分是怎么做到的
接下来我们看最后一个函数voidgame()//游戏相关操作
voidgame()
{
intx=2,y=1;//玩家当前位置,刚开始在入口处
intc;//用来接收按键
while
(1)
{
gotoxy(2*y-2,x-1);//这里的含义是到达入口处
printf("☆");//画出玩家当前位置
if(map[x][y]==End)//判断是否到达出口
{
gotoxy(30,24);
printf("到达终点,按任意键结束");
getch();
break;
}
c=get_key();
if(c==Esc)
{
gotoxy(0,24);
break;
}
switch(c)
{
caseUp:
//向上走
if(map[x-1][y]!
=Wall)
{
paint(x,y);
x--;
}
break;
caseDown:
//向下走
if(map[x+1][y]!
=Wall)
{
paint(x,y);
x++;
}
break;
caseLeft:
//向左走
if(map[x][y-1]!
=Wall)
{
paint(x,y);
y--;
}
break;
caseRight:
//向右走
if(map[x][y+1]!
=Wall)
{
paint(x,y);
y++;
}
break;
}
}
}
事实上这个函数也不是很难理解所有函数除了算法部分都不难理解,就看用不用心去读代码了
就像注释那样,gotoxy(2*y-2,x-1);到达入口处用☆当玩家,然后先进行判断是否到达终点,如果达到终点或按ESC则结束游戏,负责就开始接受按键,进行移动,说是移动实际上就是不断变化map[x][y]x和y的值并进行判断是否到达终点,按下ESC如果没有则根据x++x--y++y--来进行上下左右后改变所在二维数组中的位置打个比方
a[2][2]
分别有a[0][0]a[0][1]11
a[1][0]a[1][1]21如果处在2的位置那么按下上也就是说数组元素a[1][0]变成了a[0][0]如果用这里用a[x][y]来进行表示,那么就是等于x--;其他同理
最后我们来看一下main函数
intmain()
{
inti,j;
srand((unsigned)time(NULL));//初始化随即种子
hidden();//隐藏光标
for(i=0;i<=Height+1;i++)
for(j=0;j<=Width+1;j++)
if(i==0||i==Height+1||j==0||j==Width+1)//初始化迷宫
map[j]=Road;
elsemap[j]=Wall;
create(2*(rand()%(Height/2)+1),2*(rand()%(Width/2)+1));//从随机一个点开始生成迷宫,该点行列都为偶数
for(i=0;i<=Height+1;i++)//边界处理
{
map[0]=Wall;
map[Width+1]=Wall;
}
for(j=0;j<=Width+1;j++)//边界处理
{
map[0][j]=Wall;
map[Height+1][j]=Wall;
}
map[2][1]=Start;//给定入口
map[Height-1][Width]=End;//给定出口
for(i=1;i<=Height;i++)
for(j=1;j<=Width;j++)//画出迷宫
paint(i,j);
game();//开始游戏
getch();
return0;
}
先是srand来初始化随机种子为create打下基础
然后给map赋值输出后成四面全是墙,中间全是路的也就是000
010
000//0是墙,1是路这样
然后用create生成正式的迷宫,根据rand来随机生成路线
之后重新处理边界,以及定义入口点和出口点,可以试着删掉
for(i=0;i<=Height+1;i++)//边界处理
{
map[0]=Wall;
map[Width+1]=Wall;
}
for(j=0;j<=Width+1;j++)//边界处理
{
map[0][j]=Wall;
map[Height+1][j]=Wall;
}
这段如果在入口处按左,你会发现BUG了!
!
删掉这两段
map[2][1]=Start;//给定入口
map[Height-1][Width]=End;//给定出口
导致你一旦从入字走出,就再也走出不迷宫
最后使用print函数根据数组元素的值画出迷宫.
用game进行游戏循环并判断游戏是否结束
第一次写源码分析..蛋疼..尤其是发帖发了N次
最后..我爱C语言么么哒
给个疑惑解答:
============================================================
下面讲第二个函数
声明:
voidcreate(intx,inty)
voidcreate(intx,inty)//随机生成迷宫
{
intc[4][2]={0,1,1,0,0,-1,-1,0};//四个方向//这里的四个方向乃是0,11,00,-1-1,0代表着上下左右
inti,j,t;
//将方向打乱
for(i=0;i<4;i++)
{
j=rand()%4;
t=c[0];c[0]=c[j][0];c[j][0]=t;
t=c[1];c[1]=c[j][1];c[j][1]=t;
}
================================================================
t=c[0];c[0]=c[j][0];c[j][0]=t;
t=c[1];c[1]=c[j][1];c[j][1]=t;
我卡在这里N久
一直在想,这是个什么赋值
最后才发现原来是个错误