您好,欢迎来到化拓教育网。
搜索
您的当前位置:首页扫雷课程设计报告

扫雷课程设计报告

来源:化拓教育网


C语言程序设计报告

课程名称: 计算机课程扫雷设计

院 系: 建筑工程学院

专业班级: 土木1102班

成员姓名: 黄枭威 王晓伟 宋浩 余彬

李凯凯 李婷婷 张娣 朱月梅子

指导教师: 赵先

完成时间: 2012.6.6

报告成绩:

扫雷游戏设计

综述

在计算机逐步渗入社会生活各个层面的今天,计算机已经成为人们日常生活的一分,越来越多的人使用计算机办公、娱乐等等。

扫雷游戏是Windows操作系统自带的一款小游戏,在过去的几年里,Windows操作系统历经数次换代更新,变得越来越庞大、复杂,功能也越来越强大,但是这款小游戏依然保持原来的容貌,可见这款小游戏受到越来越多人的喜爱。我们小组利用Turbo C 编写了与它功能相仿的扫雷游戏,寓学于乐。

一、 应用环境

1.1 硬件环境

一台完整的电脑,包括键盘、鼠标,最小硬盘空间1GHz 1.1 386,486,586及兼容机.0K基本内存; 2.1 1M以上扩充内存,10M以上的显示内存.

2.2 软件环境

开发环境:本系统的设计采用的是C语言开发 Windows 操作系统,Turbo C 2.0汉化版

二、 程序的作用及设计目的

2.1 程序功能

程序的功能是随机生成地雷位置,通过键盘操作玩游戏,空格键进行打开,回车键进行标记,所有地雷标出后胜利,当单击到地雷时失败。

2.2 程序设计目的

1.培养综合运用所学知识完成课题的能力。

2.更深入地理解和掌握该课程中的有关基本概念,程序设计思想和方法。 3.提高对工作认真负责、一丝不苟,对同学团结友爱,协作攻关的基本素质。

4.培养勇于探索、严谨推理、实事求是、有错必改,用实践来检验理论,全方位考虑问题等科学技术人员应具有的素质。

5.培养从资料文献、科学实验中获得知识的能力,提高从别人经验中找到解决问题的新途径的悟性,初步培养工程意识和创新能力。

6.对掌握知识的深度、运用理论去处理问题的能力、实验能力、课程设计能力、书面及口头表达能力进行考核。

三、 程序分析和设计

3.1 游戏规则

设计30×16 格区域,按上空格键后,该格显示数字,则表示它周围8个空格内含有的地雷数,周围没有地雷的显示空白,则不能再按空格键了。如果是地雷,则游戏结束。如果判断是地雷,可以使用回车键标出,显示红旗,要取消标志则再按回车键,当所有地雷都标出,每个空格都处理过了,则结束。

3.2 游戏界面

游戏界面为30*16的黑底灰色方框。

3.3 设计思路

扫雷程序主要用了一个30行16列的二维数组表示,数组的num代表格内当前处于什么状态,值为 1 表示有雷,值为0 表示已经变成空白格或者显示过数字,roundnum统计每个格子周围有多少地雷,flag主要是空格键测试的标志,如果flag 为1 则表示格子显示红旗,这样回车键点在这个格子中将无效。

算法的重点是一开始统计好每个格子周围有多少地雷,然后当空格键点在没地雷的格子上时进行两种判断,如果格子周围没地雷就先在原来的格子位置显示空白格,然后用递归的方法同样判断周围的 8 个格子;如果格子周围有地雷,就在该格子上显示具体的雷数。

在递归判断 8 个格子时,如果格子上有雷或者格子已经显示过雷数或者空白格,以及格子上有红旗标志的话,就不再对格子进行任何判断。

1 main()主函数

定义使用到的常数、函数原型说明。然后初始化图形系统,调用游戏控制函数,游戏只接键盘标操,作按任意键结束游戏,关闭图形系统,程序结束。

2游戏控制函数

调用函数redraw重画函数,调用为具体游戏操作过程,重画游戏界面。 即对下一操作,不管是打开数字,还是空格,亦或是地雷,都重画一次。 3 画初始界面

这个函数完成初始界面的设计以及随机生成地雷数。初始界面的主要工作是确定图的位置和方格显示的位置。外边框的左上角坐标为(190 ,60),右下角坐标为(390, 290),显示地雷数的区域为(190, 60)~( 390, 90),每个方格的宽度和高度均为16。 读者可以参照修改区域的大小。 5 randlei 随机布雷

随机布雷(randlei)函数用于随机布雷,且计算每个各自周围雷的个数。 6 DrawRedflag()显示红旗

用点击回车键表示起地雷,起雷后显示一个小红旗。 7 游戏过程

游戏过程主要是对按键的处理,具体算法如下: 统计每个格子周围有多少地雷。 (1)如果单击了空格键则判断:

如果单击了方格,判断该格子里有红旗,则按键无效。如果单击的格子没有显示过数字或空白,则判断;如果是地雷,游戏结束,显示地雷分布;如果不是地雷,则统计该格子周围(8 个方向)的地雷数,如果周围地雷数为0, 调用函数tansuo处理周围格子的情况,显示周围地雷数或空白。如果单击的格子周围地雷数不为0, 则显示周围地雷数,将处理过的格子作标记。如果所有格子处理完毕,游戏胜利。

(2) 如果单击了回车键,该格子没有红旗,则显示红旗。如果有红旗,再击回车键,则红旗消失。

(3) 重复步骤(2) 直到按键结束程序。

8 统计地雷

统计每个格子周围的雷数,分别考虑格子处于四个角、四条边以及中间某个位置的情况。周围指上、下、左、右、左上、左下、右上、右下。注意程序中使用的是多个if 语句,而没有使用或运算连接组成复合表达式,考虑到 C 语言的逻辑表达式的问题,逻辑或只要前面的表达式为真,后面就不必判断了,这样可能造成少计地雷数。 9 显示无雷区的空白格

当单击了某个格子,该格子周围地雷数为0 时,应该继续判断它周围8 个方向的格子的周围地雷数是否为0 ,将这些格子都用空白显示。所以这也是一个递归问题,将其构造为递归函数。一个递归函数有两个要素,一个是入口参数,且是降规模的,另一个为出口参数。本函数的入口参数为格子的坐标,表示处理哪个格子,出口参数是该格子有红旗或者已经显示过数字或空白格子。具体算法如下:

(1) 如果当前格子有红旗或者已经显示过数字或空白格子,则返回。 (2) 空白格子数减1( 统计处理过多少格子)。

(3)如果周围的地雷数为0, 且它不是地雷,则将它显示为空白,同时将它的状态值num 置0, 表示处理过;如果周围的地雷数不为0, 显示周围地雷数,同时将它的状态值num 置0 ,表示处理过(即显示过数字),返回。

(4) 8 个方向探索调用函数显示所有的空白格子。

四、 程序测试及分析

4.1程序调试是指对程序的查错和排错。为了便于查错、阅读,在设计该程序的过程中我们采用了结构化程序方法编辑,添加了尽可能多的注释,

这就为接下来的调试过程带来了很多方便。

4.2经过仔细检查之后进行上机调试。进行编译,如果在编译和连接过程中发现错误,屏幕上显示了出错信息,根据提示找到出错的位置,加以改正,再进行编译……如此反复,直到顺利通过编译和连接为止。

4.3在本次作业过程中碰到的编译、连接的错误主要有:缺少变量定义,定义位置不正确、语法错误、注释的位置等。

4.4 错误解决方法。

(1)缺少变量定义,定义位置不正确;

由于该程序相对来讲稍有些长,前后有些变量不容易联系起来,但是在错误信息的提示下一般还是很容易找到。不过需要注意的是在定义的时候有些函数使用同样的变量名而表示不同的作用,因而使用要很小心,定义及定义的位置要特别留意。为减少这样的错误我后来还是用不同的变量名来表示,结果引起的那些错误解决了。

(2)语法错误;

大多的语法错误在通过书本参考下能够修改。主要是平时缺乏锻炼、不太注意而产生的。如没有注意具体数据使用是有一定的范围限定;过分重视分号的重要性而在for、if、while语句中画蛇添足加分号;在使用文件的时候忘记将文件先打开,对打开的方式

(3)注释的位置;

程序设计中在注释的时候不能同我们平常写字一样随心所欲,我们应该注意注释的格式。且注释中能含有C语言可执行的语句。

五、 心得体会

课程设计是本科学习阶段一次非常难得的理论与实际相结合的机会,通过这次比较完整的一个程序的设计,我摆脱了单纯的理论知识学习状态。以前在课堂上因为有老师辅导、而且学习时每次的代码作业都是局限的一段,所以从未料想到一个游戏程序的整体把握还是有一定难度的,代码每一个地方都是有联系的,一个地方错,其他地方都会错。

————————黄枭威

实际设计的结合锻炼了我的综合运用所学的基础知识,解决实际问题的能力,同时也提高我查阅文献资料、对程序整体的把握等其他能力水平。我现在才发现以前在课堂学的东西还不够,很多都是要靠我们举一反三,此次的游戏设计让我发现,代码不管怎么变,思维是不变的,其中的思想很多是很相似的。

————————王晓伟

通过对整体的掌控,对局部的取舍,以及对细节的斟酌处理,都使我的能力得到了锻炼,经验得到了丰富。我再不会像以前那样看到代码就会头疼,因为通过此次作业我学习了C语言的数据类型、常量与符号常量、变量、C语言的运算符和表达式、赋值运算符和赋值表达式、自增自减运算符以及逗号表达式等。

——————————宋浩

愉快的合作,共同付出,然后收获,这是我们都希望看到的也正是我们进行课程设计的目的所在。而且我也明白了C语言的简洁,使用灵活方便,运算符丰富,表达能力强。还有数计类型丰富,目标程序质量高,具有面向硬件系统的特点,具有结构化的控制语句和模块化的程序结构,具有编译预

处理功能,而且程序设计自由度大,可移植性好。

——————————李凯凯

虽然设计内容繁多,过程繁琐但我的收获却更加丰富。各种组件的运用,各种算法的应用,各种控件的利用我都是随着设计的不断深入而不断熟悉并逐步掌握的。从而启发我,要想写好程序,在写好课本知识的同时还需要多读和专业有关的一些书籍,同时还需要多动脑子,尽量把所学的知识综合起来应用,力争写出完美的程序。

——————————李婷婷

和老师以及同学的沟通交流更使我对程序整体的规划与设计有了新的认识也对自己提出了新的要求。本程序在刚开始调试时有许多错误,但在我的努力及同学的帮助下都被一一克服,在刚开始的几次调试中曾经出现过不能运行等等问题。经过我的努力及同学的帮助,这些问题得到克服,并且使程序的功能也得到了一定的完善

———————————张娣

提高是有限的但提高也是全面的,正是这一次设计让我积累了许多实际经验,也必然会让我在未来的工作学习中表现出更高的应变能力和理解力除此之外,我还得到了一些有用的教训:写程序时必须要细心,不能输错一个字符标点,就连全角半角也得注意。在修改时要有耐心,编译出错后必须逐个错误去改正,绝不能心急浮躁,否则修改之后还会有新的错误。

————————————余彬 顺利如期的完成本次课程设计给了我很大的信心,但是也让多不足的地方,学习其实就是一个不断完善的过程,正视自己的不足之处,在以后的工

作和学习中不断的弥补这些不足之处,在以后的生活中也要保持同样的态度,不断的完善自己。。在这次设计过程中,不仅复习课本上所学知识,还通过查资料、问同学学到了课本上没有的知识。

——————————朱月梅子

六、 总结

6.1 知识点

1 数组的应用。 2 全局变量的应用。 3 按键的处理。 4 探索函数。

5. 功能扩充、

修改程序,设初级、中级、高级三个等级,初级地雷数较少,在15 个以内,中级在

15 到30 个,高级则扩大棋盘为20×20, 地雷数为 30 个以上。

七、主要代码

#include #include #include #include

/*定义几个游戏中要用到的功能按键*/ #define ESC 0x11b #define UP 0x4800 #define DOWN 0x5000 #define LEFT 0x4b00 #define RIGHT 0x4d00 #define SPACE 0x3920 #define ENTER 0x1c0d

int a[50][50]={0}; /*存放雷的数组*/ int b[50][50]={0}; /*存放格子状态的数组*/

char num[9][2]={\"?\

int gbx=320,gby=240; /*当前光标位置 (0,0)表示左上角*/

int ii,jj; main() {

int i,j,m=30,n=16,d=20,k; int gdriver = DETECT, gmode; randlei(30,16,100); ii=m/2;jj=n/2;

registerbgidriver(gdriver);

initgraph(&gdriver, &gmode, \"c:\\\urboc2\"); wangge(m,n,d); redraw(m,n,d);

while(1) /*反复从键盘获得程序需要的按键*/ {

if(bioskey(1)) /*判断是否有按键*/ {

k=bioskey(0); switch(k) { case ESC:

exit(0);break; case UP: if(jj>1) {

jj-=1;

redraw(m,n,d);

} break; case DOWN:

if(jjjj+=1;

redraw(m,n,d); } break;

case LEFT: /*LEFT 键向下移动光标*/ if(ii>1) {

ii-=1;

redraw(m,n,d); } break;

case RIGHT: /*RIGHT 键向下移动光标*/ if(iiii+=1;

redraw(m,n,d); }

break;

case SPACE: /*空格键认为无雷打开*/ {

b[jj][ii]=1; if(a[jj][ii]==0) tansuo(jj,ii,n,m); }

redraw(m,n,d); break;

case ENTER: /*回车键认为有雷标记*/ if(b[jj][ii]==0)b[jj][ii]=-1;

else if(b[jj][ii]==-1)b[jj][ii]=2;

else if(b[jj][ii]==2)b[jj][ii]=0;

redraw(m,n,d);

break; }

}

} getch();

closegraph(); } /*

redraw重画函数在用户有操作后,重画游戏画面 */

redraw(int m,int n,int d) {

int i,j; wangge(m,n,d); for(i=1;i<=n;i++) for(j=1;j<=m;j++) {

if(b[i][j]!=1) gezi3d(320+(j-1-m/2)*d,240+(i-1-n/2)*d,d); else

if(a[i][j]>=0) {

gezi2d(320+(j-1-m/2)*d,240+(i-1-n/2)*d,d); if(a[i][j]>0) {

shownum(320+(j-1-m/2)*d,240+(i-1-n/2)*d,d,a[i][j]); }

}

else drawlei(320+(j-1-m/2)*d,240+(i-1-n/2)*d,d,a[i][j]);

if(b[i][j]==-1)showflag(320+(j-1-m/2)*d,240+(i-1-n/2)*d,d);

if(b[i][j]==2)shownum(320+(j-1-m/2)*d,240+(i-1-n/2)*d,d,0); }

gbx=320+(ii-1-m/2)*d; gby=240+(jj-1-n/2)*d; drawGB(gbx,gby,d); } /*

随机布雷(randlei)函数用于随机布雷,且计算每个各自周围雷的个数

Int m : 横向各自的数量 要求是双数 Int n : 纵向格子的数量 要求是双数 Int num : 雷的个数 */

randlei(int m,int n,int num) {

int i,j,xx,yy,sum=0,t; srand(time(NULL)); do {

t=random(m*n); xx=t/m+1; yy=t%m+1; if(a[xx][yy]==0) {

a[xx][yy]=-1; sum++; }

}while(sumif(a[i][j]!=-1) {

if(a[i-1][j-1]==-1)a[i][j]++; if(a[i-1][j]==-1)a[i][j]++; if(a[i-1][j+1]==-1)a[i][j]++; if(a[i][j-1]==-1)a[i][j]++; if(a[i][j+1]==-1)a[i][j]++; if(a[i+1][j-1]==-1)a[i][j]++; if(a[i+1][j]==-1)a[i][j]++; if(a[i+1][j+1]==-1)a[i][j]++; } } }

wangge(int m,int n,int d) {

int i,j;

setcolor(7); /*网格区域填充浅灰色底色*/ setfillstyle(1,7);

bar(320-m/2*d,240-n/2*d,320+m/2*d,240+n/2*d); setcolor(15);

for(i=320-m/2*d;i<320+m/2*d;i=i+d) /*小格子起点的横坐标序

列*/

for(j=240-n/2*d;j<240+n/2*d;j=j+d) /*小格子起点的纵坐标序列*/

;/* gezi3d(i,j,d); */ /*绘制一个立体效果的小格子*/ } /*

画雷(drawlei)函数用于绘制给定坐标位置的雷 雷画在格子的正中心

Int x : 雷所在格子左上角点横坐标 Int y : 雷所在格子左上角点纵坐标 Int d : 格子间的间距 */

drawlei(int x,int y,int d) { int r;

setcolor(0); /*雷颜色为黑色*/ for(r=d/4;r>0;r--)

circle(x+d/2,y+d/2,r); /*画多个小园形成雷外壳*/ line(x+d/2,y+3,x+d/2,y+d-3); /*画雷外壳上的刺*/ line(x+3,y+d/2,x+d-3,y+d/2); line(x+5,y+5,x+d-5,y+d-5); line(x+5,y+d-5,x+d-5,y+5);

} /*

显示数字(shownum)函数用于显示给定坐标位置的数字 数字显示在格子的正中心

lnt x : 数字所在格子左上角点横坐标 lnt y : 数字所在格子左上角点纵坐标 int d : 格子间的间距 int n : 要显示的数字 */

shownum(int x,int y,int d,int n) {

setcolor(0+n); /*数字颜色为黑色*/ settextstyle(SMALL_FONT,HORIZ_DIR,0); outtextxy(x+0.3*d,y+0.4*d,num[n]); } /*

显示旗子(showflag)函数用于显示给定坐标位置的标志为雷的小红旗

int x : 旗子所在格子左上角点横坐标 int y : 旗子所在格子左上角点纵坐标 int d : 格子间的间距 */

showflag(int x,int y,int d) { int k,l; setcolor(4);

for(l=1,k=y+0.2*d;k<=y+0.5*d;l=l+1.5,k++) line(x+d/2-1,k,x+d/2,k); setcolor(0);

line(x+d/2,y+d/2,x+d/2,y+d*0.8); line(x+d*0.2,y+d*0.8,x+d*0.8,y+d*0.8);

line(x+d*0.2-1,y+d*0.8+1,x+d*0.8+1,y+d*0.8+1); } /*

绘制三维小格子(gezi3d)函数用于将扫雷界面的每个小格子绘制为三维效果

这是该格子未被打开时的效果

int x : 旗子所在格子左上角点横坐标 int y : 旗子所在格子左上角点纵坐标 int d : 格子间的间距 */

gezi3d(int x,int y,int d) {

setcolor(8); line(x,y,x,y+d);

line(x,y,x+d,y); line(x+d,y+d,x,y+d); line(x+d,y+d,x+d,y); setcolor(15);

line(x+1,y+1,x+1,y+d-1); line(x+1,y+1,x+d-1,y+1); setcolor(0);

line(x+d-1,y+d-1,x+1,y+d-1); line(x+d-1,y+d-1,x+d-1,y+1); } /*

绘制二维小格子(gezi3d)函数用于将扫雷界面的每个小格子绘制为二维效果

这是该格子未被打开时的效果

int x : 旗子所在格子左上角点横坐标 int y : 旗子所在格子左上角点纵坐标 int d : 格子间的间距 */

gezi2d(int x,int y,int d) {

setcolor(8); line(x,y,x,y+d);

line(x,y,x+d,y); line(x+d,y+d,x,y+d); line(x+d,y+d,x+d,y); setfillstyle(1,7); bar(x+1,y+1,y+d-1,y+d-1); } /*

画爆炸雷(drawBZlei)函数用于绘制给定坐标位置的爆炸雷 雷画在格子的正中心 格子背景色为红色 int x : 旗子所在格子左上角点横坐标 int y : 旗子所在格子左上角点纵坐标 int d : 格子间的间距 */

drawBZlei(int x,int y,int d) { int r; setcolor(4); setfillstyle(1,4); bar(x+1,y+1,x+d-1,y+d-1); setcolor(0); for(r=d/4;r>0;r--) circle(x+d/2,y+d/2,r); line(x+d/2,y+3,x+d/2,y+d-3);

line(x+3,y+d/2,x+d-3,y+d/2); line(x+5,y+5,x+d-5,y+d-5); line(x-5,y+d-5,x+d-5,y+5); }/*

画光标(drawGB)函数用于绘制给定坐标位置的光标 光标为一个蓝色正方形

int x : 旗子所在格子左上角点横坐标 int y : 旗子所在格子左上角点纵坐标 int d : 格子间的间距 */

drawGB(int x,int y,int d) { int r; setcolor(1); for(r=1;r<=2;r++)

rectangle(x+r,y+r,x+d-r,y+d-r); }

tansuo(int x,int y,int m,int n) {

if(b[x][y-1]==0 && y-1>=1 ) {

b[x][y-1]=1;

if(a[x][y-1]==0)tansuo(x,y-1,m,n);

}

if(b[x+1][y]==0 && x+1<=m) {

b[x+1][y]=1;

if(a[x+1][y]==0)tansuo(x+1,y,m,n); }

if(b[x-1][y]==0 && x-1>=1) {

b[x-1][y]=1;

if(a[x-1][y]==0)tansuo(x-1,y,m,n); }

if(b[x][y+1]==0 && y+1<=n) {

b[x][y+1]=1;

if(a[x][y+1]==0)tansuo(x,y+1,m,n); }

if(b[x-1][y-1]==0 && y-1>=1 && x-1>=1) {

b[x-1][y-1]=1;

if(a[x-1][y-1]==0)tansuo(x-1,y-1,m,n); }

if(b[x-1][y+1]==0 && y+1<=n && x-1>=1)

{

b[x-1][y+1]=1;

if(a[x-1][y+1]==0)tansuo(x-1,y+1,m,n); }

if(b[x+1][y-1]==0 && y-1>=1 && x+1<=m) {

b[x+1][y-1]=1;

if(a[x+1][y-1]==0)tansuo(x+1,y-1,m,m); }

if(b[x+1][y+1]==0 && y+1<=n && x+1<=m) {

b[x+1][y+1]=1;

if(a[x+1][y+1]==0)tansuo(x+1,y+1,m,n); }

if(b[x+1][y+1]==0 && y+1<=n && x+1<=m) {

b[x+1][y+1]=1;

if(a[x+1][y+1]==0)tansuo(x+1,y+1,m,n); } }

八、游戏界面

游戏初始界面如图8-1 所示 , 游戏中的界面如图8-2 所示。

图8-1 初始状态

图8-2 游戏中

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo9.cn 版权所有 赣ICP备2023008801号-1

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务