扫雷设计报告.docx
《扫雷设计报告.docx》由会员分享,可在线阅读,更多相关《扫雷设计报告.docx(21页珍藏版)》请在冰豆网上搜索。
扫雷设计报告
..
HarbinInstituteofTechnology
课程设计报告
课程名称:
数据结构与算法课程设计
设计题目:
扫雷游戏
院系:
计算机科学与技术学院
班级:
10503105
设计者:
黄林峰
学号:
1050310521
指导教师:
李秀坤
设计时间:
2007年9月8日
哈尔滨工业大学
;.
..
哈尔滨工业大学课程设计任务书
姓
名:
黄林峰
院(系):
计算机科学与技术
专
业:
计算机科学与技术
班
号:
10503105
任务起至日期:
2007年
8月27
日
至
2007年
9月
9日
课程设计题目:
扫雷游戏
课程设计要求:
1、做一个NxM的扫雷游戏(如下图),每个方格包含两种状态:
关闭(closed)
和打开(opened),初始化时每个方格都是关闭的,一个打开的方格也会包
含两种状态:
一个数字(clue)和一个雷(bomb)。
你可以打开(open)一个方格,如果你打开的是一个bomb,那么就失败;否则就会打开一个数字,
该数字是位于[0,8]的一个整数,该数字表示其所有邻居方格(neighboringsquares)所包含的雷数,应用该信息可以帮助你扫雷。
2、能够给出游戏结果(输、赢、剩余的雷数、用掉的时间按秒计)
3、游戏界面最好图形化,否则一定要清楚的字符界面。
4、合理分配各个操作的按键,以及各方格各种状态如何合理显示。
;.
..
设计任务总述:
1、利用二维数组建立一个NxM的区间,初始化每个方格关闭。
2、用户能够打开一个方格,一个已打开的方格不能再关闭。
3、能够标记一个方格,标记方格的含义是对该方格有雷的预测(并不表示真
的一定有雷),当一个方格标记后该方格不能被打开,只能执行取消标记的操作,只能在取消后才能打开一个方格。
4、对打开的方格进行判断,如果打开的是一个bomb,则gameover;反之,
显示某一数字,即所有邻居方格所包含的雷数
5、在游戏界面上,显示输、赢、剩余的雷数以及用掉的时间。
工作计划及安排
:
月28
日~8
月31
日对VC图形化界面的使用进行学习,
初步准备在TC3.0
1、8
编译环境下,利用TC自带的绘图函数做出图形界面。
在此期间,参看有关讲解TC函数的书籍,对所需函数灵活运用。
2、9月1日开始进行编程,绘出图形,写出鼠标控制函数。
3、中期检查之前要把主要的图形以及各鼠标控制做出,9月3日之后开始编
写完整的程序,调试。
4、9月8日之前完成报告的撰写以及答辩PPT。
指导教师签字___________________
年月日
;.
..
数据结构与算法课程设计中期检查结果
学号:
10503105姓名:
黄林峰指导老师:
李秀坤
课程设计题目扫雷游戏
系统总任务描述:
本题目做一个NxM的扫雷游戏,每个方格包含两种状态:
关闭(closed)
和打开(opened),初始化时每个方格都是关闭的,一个打开的方格也会包含两种状态:
一个
数字(clue)和一个雷(bomb)。
你可以打开(open)一个方格,如果你打开的是一个bomb,
那么就失败;否则就会打开一个数字,该数字是位于[0,8]的一个整数,该数字表示其所有邻居
方格(neighboringsquares)所包含的雷数。
能够打开一个方格,一个已打开的方格不能再关闭。
能够标记一个方格,标记方格的含义是对该方格有雷的预测(并不表示真的一定有雷),
当一个方格标记后该方格不能被打开,只能执行取消标记的操作,只能在取消后才能打开一个
方格。
能够给出游戏结果。
游戏界面图形化。
;.
..
已完成工作描述:
1.确定在TurboC/C++3.0的平台上,利用DOS系统调用函数和graphics.h进行图形化处理。
2.
查阅相关资料,完成如下模块:
InitMouse,Scr,MouseState,Edge,TurnBack,
InitArrow,InitCursor
,MouseShow,MouseHide,CursorShow,CursorHide,SetRange,
GetXY,SetXY,WaitMouse,WaitKey,Prt,Locate。
3.
程序上,已经完成了利用
random(随机数产生函数)在区域里布雷,若重复布雷,则
进行一次判断,再随机一次(用
while循环实现),code如下:
for(i=0;i<10;i++)
{
x=random(10);
y=random(10);
while(Mine[y][x])
{
x=random(10);
y=random(10);
}
Mine[y][x]=MINE;
}
4.对任意一个不是雷的小块周围8块依次判断,确定其周围的雷数:
if(Mine[y][x]!
=MINE)
{
if((Mine[y][x-1]==MINE)&&((x-1)>=0))i++;if((Mine[y][x+1]==MINE)&&((x+1)<10))i++;if((Mine[y-1][x]==MINE)&&((y-1)>=0))i++;if((Mine[y+1][x]==MINE)&&((y+1)<10))i++;
if((Mine[y-1][x-1]==MINE)&&((x-1)>=0)&&((y-1)>=0))i++;if((Mine[y-1][x+1]==MINE)&&((x+1)<10)&&((y-1)>=0))i++;if((Mine[y+1][x+1]==MINE)&&((x+1)<10)&&((y+1)<10))i++;if((Mine[y+1][x-1]==MINE)&&((x-1)>=0)&&((y+1)<10))i++;
Mine[y][x]=i;
}
;.
..
下一步工作计划及安排:
1.查阅相关资料,进一步处理光标和箭头的函数模块。
2.编写FailExitGame和ExitGame的函数,区分两种不同方式的Exit。
3.编写计时函数。
4.把各模块拼装成一整体,调试程序。
5.完成报告和PPT。
;.
..
填表时间:
2007年9月3日指导教师签字:
一、题目分析
游戏开始时,系统会在雷区的某些小方块中随机布下若干地雷。
安排放好的地雷小方块
称之为雷方块,其他的称之为非雷方块。
部署完毕后,系统会在其他非雷方块中填充一些数
字。
某一个具体的数字表示与其紧邻的8个方块中有多少雷方块,例如“1”就表示紧邻8
个方块中有一个雷方块。
玩家可以根据这些信息去判断是否可以打开某些方块,并把认为可
能是地雷的方块打上标识。
当玩家将所有地雷找出后,其余的非雷方块区域都已经打开,此时游戏胜利结束。
在游戏过程中,一旦错误地打开了雷方块,即立即失败,游戏结束。
图1
Windows下扫雷胜利的情形
;.
..
图2
Windows下扫雷失败情形
二、总体设计
基于上面对Windows扫雷游戏的分析,可以总结出游戏的总体结构:
该游戏主要包含如下三个阶段:
随机布雷,扫雷过程和结果显示。
布雷:
开始
否是
生成随机的雷方块的坐标
(x,y)
判断(x,y)
区域是否已经布
下雷
在(x,y)区域布雷,修改状态
数据
;.
..
判断是否布下
所有的雷
结束
扫雷:
鼠标左键事件
开始
在雷区
雷方块定位
游戏结束
继续处理
其
胜利
他
区
打开区域
失败处理
域
胜利处理
处
理
拓展最大可
;.
能显示范围
..
鼠标右键事件
鼠标右键
雷方块定位
判断历史属性以及相关状态
修改相关状态
显示
结束
;.
..
三、数据结构设计
在程序中,我设定了如下几种数据结构来实现功能:
1.定义一个二维数组Mine[10][10]存放雷的信息,定义二维数组Turn[10][10]存放右键信息。
2.在鼠标函数的编写中,用了一个REGS的共用体类型,该共用体的成员由结构类型的x和
h组成,其中x代表16位寄存器变量,它的成员用CPU的相关寄存器名表示。
结构类型h
代表8位寄存器变量,其成员与相关的CPU的8位寄存器同名。
3.中断的调用。
在程序中一共使用了两种软中断调用方式,int86()和geninterrupt()。
四、算法设计
该游戏算法并不复杂,主要集中在布雷和扫雷过程中。
一、布雷
开始时,利用C语言中随机数的生成函数random在已经初始设空(NULL)的区域内布10个雷。
如果重复,重新布一次。
二、设置雷区下数值
当雷布好后,就进入了其他非雷区域设定阶段。
由于雷是随机布放的,没有类的地方被点击后就会显示一个数字,表示它周围有几个雷。
因此,可以把整个雷区看成如下所示的一个二维数组
1112131415161718
2122232425262728
a[i,j]=3132333435363738
4142434445464748
5152535455565758
假若要知道a[3,4]周围有几个雷,就必须检测下面
8个雷区是否放上了雷。
a[2,3]
a[2,4]
a[2,5]
a[3,3]
a[3,5]
a[4,3]
a[4,4]
a[4,5]
仔细观察它们存在的数学关系,发现
a[i,j]周围的雷个数是由这样
8个雷区决定的(如果超
出了边界,应再加以判断):
a[i-1,j-1]
a[i-1,j]
a[i-1,j+1]
a[i,j-1]
a[i,j+1]
a[i+1,j-1]
a[i+1,j]
a[i+1,j+1]
三、玩家按键
最后就是处理玩家在游戏过程中的按键。
玩家有两种鼠标按键选择,左键和右键。
此外,玩
;.
..
家还可能键盘按键,而该游戏中主要是提供鼠标按键,所以必须对用户按了什么键首先判断。
用户按Esc键时退出游戏;按鼠标左键时,进一步判断是否是雷;按右键时,标记可能是雷
的区块,并及时修改Mines剩余值。
若在已经标记过的区块再点一次右键,则取消标记。
五、物理实现
一、鼠标编程
由于该游戏的特点,在编游戏的开始阶段我就选择了利用TurboC调用中断,编写一组鼠标
操作函数。
鼠标驱动程序提供了一个标准的软件中断接口,在加载了鼠标驱动程序之后,无论鼠标的类
型如何,应用程序都可以直接通过该软件接口操作鼠标。
该接口的中断号为INT33H,其使
用方法和其他BIOS的中断调用完全相同。
以下,介绍程序中主要的几个鼠标函数:
(1)初始化鼠标函数InitMouse():
该函数用于判断是否安装了鼠标及其驱动程序,如果
是,初始化鼠标驱动程序并返回鼠标的按钮数(2或3);否则返回0。
该函数调用
了INT33H的00H号功能。
BYTEInitMouse()
{
unionREGSregs;
regs.x.ax=0;
int86(MOUSE,®s,®s);
return(regs.x.ax);
}
(2)
显示鼠标光标函数
MouseShow():
鼠标光标在文本显示下是个矩形光标,在图形方
式下是一个箭头。
用户移动鼠标,则光标随之移动。
该函数调用了
INT33H
的01H
号功能。
voidMouseShow()
{
unionREGSregs;
regs.x.ax=1;
int86(MOUSE,®s,®s);
}
(3)
隐藏鼠标光标函数
MouseHide():
大体同
(2),只是该函数调用了
INT33H
的02H
号功能。
(4)读鼠标状态函数GetXY():
该函数调用了INT33H的03H号功能。
voidGetXY(int*x,int*y)
{
unionREGSireg,oreg;
ireg.x.ax=3;
int86(MOUSE,&ireg,&oreg);
*x=oreg.x.cx;
*y=oreg.x.dx;
}
参数x和y存放的是读出的鼠标坐标。
;.
..
这里值得特别注意的是,如果是在文本方式(80x25)下,此时鼠标所在的文本行、列位置与其坐标之间存在如下关系:
鼠标所在的文本列=x/8;
鼠标所在的文本行=y/8;
(5)设置鼠标光标位置的函数SetXY():
该函数调用了INT33H的04H号功能。
voidSetXY(intx,inty)
{
unionREGSireg;
ireg.x.ax=4;
ireg.x.cx=x;
ireg.x.dx=y;
int86(MOUSE,&ireg,&ireg);
}
参数x和y存放的是欲设置的鼠标光标坐标。
这里值得特别注意的是,如果是在图形方式下,按图形方式的实际坐标设置;如果是在文本方式下,此时鼠标光标坐标与鼠标所在的文本行、列存在如下关系:
x=鼠标所在的文本列*8;
y=鼠标所在的文本行*8;
(6)
设置鼠标活动范围函数
SetRange():
该函数调用了
INT33H的07H号功能将鼠标的
移动范围限制在屏幕上的一个矩形区域内。
voidSetRange(intstart_x,intstart_y,intend_x,intend_y)
{
unionREGSr;
r.x.ax=7;
r.x.cx=start_x;
r.x.dx=end_x;
int86(0x33,&r,&r);
r.x.ax=8;
r.x.cx=start_y;
r.x.dx=end_y;
int86(MOUSE,&r,&r);
}
二、随机布雷
初始化随机数发生器randomize();
利用循环,初始设空:
for(y=0;y<10;y++)
for(x=0;x<10;x++)
{
Mine[y][x]=NULL;
Turn[y][x]=FALSE;
}
开始布雷,前后布在同一块的话就利用while循环重新布一次:
for(i=0;i<10;i++)
;.
..
{
x=random(10);
y=random(10);
while(Mine[y][x])
{
x=random(10);
y=random(10);
}
Mine[y][x]=MINE;
}
三、设置雷区下数值
对任一块雷区周围的8块雷区进行扫描,依次累加到i上,最后i值即为点开该雷块应显示的数值。
可由如下算法实现
Inti=0;
if(Mine[y][x]!
=MINE)
{
if((Mine[y][x-1]==MINE)&&((x-1)>=0))i++;
if((Mine[y][x+1]==MINE)&&((x+1)<10))i++;
if((Mine[y-1][x]==MINE)&&((y-1)>=0))i++;
if((Mine[y+1][x]==MINE)&&((y+1)<10))i++;
if((Mine[y-1][x-1]==MINE)&&((x-1)>=0)&&((y-1)>=0))i++;
if((Mine[y-1][x+1]==MINE)&&((x+1)<10)&&((y-1)>=0))i++;
if((Mine[y+1][x+1]==MINE)&&((x+1)<10)&&((y+1)<10))i++;
if((Mine[y+1][x-1]==MINE)&&((x-1)>=0)&&((y+1)<10))i++;
Mine[y][x]=i;
}
四、标记雷块
建立一个二维数组Turn[y][x],专门记录用户右键的情况,当用户第一次按右键的时候,修
改Turn[y][x]的值,使之为2,并把该模块标记为“*”,同时Total的值自加1;当用户在该模块上第二次点右键的时候,修改Turn[y][x]的值为0,并把该模块重新标记为初始的“?
”,同时Total的值自减1。
五、游戏结束
游戏有四种结束方式:
1.
用户按Esc键强行退出;
2.
用户点击雷块,游戏失败退出
FailExitGame():
for(y=0;y<10;y++)
for(x=0;x<10;x++)
if(Mine[y][x]==MINE)Prt(x+SX,y+SY,'*',14+128);
MouseHide();
CursorShow();
;.
..
printf("\nFail!
\n");
delay(4000);
exit(0);
3.用户标注完10个雷块,但其中有误标注,游戏失败退出FailExitGame():
for(i=0;i<10;i++)
if(Mine[Mark[i][1]][Mark[i][0]])m++;
if(m<9)FailExitGame();
4.用户找出所有的10个雷块,游戏胜利退出ExitGame():
for(i=0;i<10;i++)
if(Mine[Mark[i][1]][Mark[i][0]])m++;
if(m<9)FailExitGame();
MouseHide();
CursorShow();
printf("\nOK,Good!
\n");
delay(4000);
exit
(1);
六、运行结果
开始界面:
图3开始界面
用户点击雷块,游戏失败:
;.
..
图4点击雷块游戏失败
用户标注完10个雷块,但其中有误标注,游戏失败:
图5标注完毕但有错误
找出所有的10个雷块,游戏胜利:
;.
..
图6游戏胜利
七、结果分析
从最后的执行文件可以看出,本课程设计最终设计的扫雷小游戏基本可以完成了预定目标,有一个遗憾,就是没有记录用户所耗时间的功能。
在TC3.0的环境下,利用窗口图形实现了鼠标控制的要求。
在程序判断上没有明显的问题,能够满足初级用户的要求。
八、结论
本次课程设计完成了扫雷游戏的模拟,并给出了相应的图形化界面。
通过本次课程设计,训练了对二维数组,中断函数等C语言基础知识的应用和掌握,并对图形界面的程序设计有了一定的锻炼。
九、参考文献
1.冯博琴,刘路放,精讲多练
C语言,西安交通大学出版社,1997。
2.杨路明,C语言程序设计教程,北京邮电大学出版社,
2003。
3.罗伟坚,VisualC++经典游戏程序设计,人民邮电出版社,
2004。
;.