版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、C语言程序设计报告题目:扫雷游戏 班级:网101 组长:目录成员:, 日期:一基本情况二游戏规则三设计思路霍谢I四函数说明1 .游戏控制部分mH2 .图形处理部分3 .鼠标处理部分五调试与测试六附录一基本情况开发平台: win-tc (windows-xp)开发进度: 小组进行图形处理及鼠标相关资料收集,掌握相关图形处理及 鼠标相关技术小组成员讨论程序实现算法及任务分配代码实现,调试任务划分:陈超负责程序总体设计,游戏控制部分实现,后期调试张艳负责程序图形处理及鼠标处理部分实现,总结文档编写二游戏规则玩家进入游戏界面后,只能通过鼠标进行操作,一旦有键盘输入,则退出游 戏程序。游戏框图左上方显示
2、的数字为此局游戏中包含的地雷数目。中问黄 色笑脸为重新开始按钮,一旦鼠标左键单击此位置,则退出正在进行的扫雷 游戏,游戏重新开始。游戏中包含 10*10个空格,可以通过鼠标左键单击或 者右键单击来进行扫雷游戏。鼠标单击表示打开此空格位置,若此位置为地 雷,则输出所有的地雷分布,玩家输,游戏结束,等待玩家的选择退出或者 继续开始下一次游戏。若此位置已经被左单击过,则再次进行鼠标左键单击 时,游戏不做任何响应。单击过后若此位置无雷则显示空格或者数字。空格 表示此处无雷,数字表示此处无雷且周围八个格子中的地雷数目为空格中的 数字数目,若某个空格周围亦没有地雷分布则继续以每个方格为中心继续判 断无雷就
3、展开,显示数字或者空格,直至遇到地雷或者是边界。鼠标右键单 击表示游戏玩家标识此位置为地雷,若游戏玩家在某位置右键单击过之后, 再次右键单击此位置,则表示取消此处标注的地雷标志,若在此处鼠标左键 单击,不做任何响应。游戏玩家依次对每一个空格,当游戏玩家把所有的非 雷区域全部处理完毕,则游戏结束,玩家胜利,输出“ YOU WIN',等待玩家 进一步选择。三设计思路扫雷程序主要用了一个10行10列的二维数组,数组的每个元素都是结构体类型,结构体中的num代表格内当前处于什么状态,值 1表示有雷,值0表示已经变成空白格或者显示过数字,roundnum统计每个格子周围有多少地雷, flag是鼠
4、标右键的标志,如果鼠标左键单击此方格,则对应的二维数组结构体里 的flag为1表示格子显示红旗,这样鼠标左键点击在这个格子上无效。首先通过生成随机数的方式布置地雷,如果在该点生成的随机数为 1,则该 点存在地雷,将NUM (结构体)标为1,随机数为其它值NUM (结构体)标为 0,每生成一个地雷,则全局变量 minenum自增一。在程序一开始统计好每个格子周围有多少地雷,将统计的结果存放在对应 的结构体变量roundnum,然后当鼠标左键点击在没有地雷的格子上时进行两种 判断,如果格子周围没有地雷,就在原来的格子位置显示空白格, 然后用递归的 方法同样判断周围的%个格子;如果格子周围有地雷m就
5、在该空格显示具体的雷 数。mMF w,1 Mb JHf在递归判断毛个格子时,如果格者犷?经显示过雷数或者空 白,以及格子上有红旗标志的话,就不再对格子进行任何判断。否则,当此处无 雷,即展开此处,并且以此位置为中心继续进行递归,直至遇到边界或者地雷, 跳出递归。当游戏玩家每处理一个非雷区域的格子,则对应的统计非雷方格数目的变 量自减一,当该变量的值自减为 0时,则表示游戏结束,该玩家胜利。具体函数流程图如下:Main四函数说明1游戏控制部分A. main ()主函数定义使用到的常数,全局变量,函数原型说明。然后初始化图形系统,调 用游戏控制函数,按任意键结束游戏,关闭图形系统,游戏结束。B.
6、void SpreadMine(intt)布雷函数通过函数srand(int)time(0);生成随机数,随后在二重循环里,生成随机 数,若生成的随机数为1,则将num (结构体)标为1,表示改点有雷,并在该 函数内统计该次游戏中地雷总数,通过 outtextxy(210,70,randminenum);在(210, 70)点输出雷的总数,用一百减去总雷数表示该次无雷空格的总数 (在输赢判断 中,若所有无雷区域都已经得到了处理,即玩家胜利)。C. void GameOver循戏结束如果单击了地雷,则地雷爆炸,游戏结束,显示地雷分布,两重循环 判断每个格子的状态,如果状态值为1,则为地雷,设置红
7、色背景,实体填充模 式,画圆表示地雷。win信息。D. void GameWin(玩家胜利,就表示游戏玩家胜利,输出youGameBegain(游戏开始这个函数完成初始界面的设计以及调用函数 void SpreadMine(int t)生成 地雷。初始界面的主要工作是确定图的位置和方格显示的位置。 外边框的左上角 为( 190, 60),右上角坐标为(390, 290),显示笑脸和地雷数的区域为(190,60) (390, 90),每个方格的宽度和高度均为 16.F. void ShowWhite(int i,int j)显示空白区域当单击某个格子,该格子周围白地雷数为0时,应该继续判断它周围
8、8个方 向的格子的周围的雷数是否为 0,将这些格子都用空白显示。具体实现如下:a如果当前格子有红旗或者已经显示过数字或空白格子,则返回。b空白格子数减一(统计处理过多少格子)。c如果周围的地雷数为0,且它不是地雷,则将它显示为空白,同时将它的状 态值num置0,表示处理过;如果周围地雷数不为 0,显示周围地雷数,同时将 它的状态值num置0,表示处理过,返回。G. void Control。调用函数GameBegain()显示游戏初始化界面,调用 GamePlay()函数 具体实现游戏操作,该函数的返回值有可能有两种:一是正在玩中,提前结束游 戏;一是玩完,要么失败,要么胜利。如果是前者,则重
9、新开始游戏。如果是后 者,则判断是否单击了笑脸,是则重新开始,否则结束程序。H. void GamePlay(游戏控制游戏过程主要是对鼠标按键的处理,集体算法实现如下:a.如果单击了鼠标左键则判断如果单击了笑脸,则游戏重新开始如果单击了方格,判断该格子有红旗,则按键无效。如果单击的格子没有显示 过数字或空白,则判断:如果是地雷,游戏结束,显示地雷分布;如果不是地雷, 则统计周围(8个方向)的地雷数,如果周围地雷数为0,条用递归函数ShowWhite()处理周围格子的情况,显示周围的格子数或者空白。如果单击的格子周围地 雷数不为0,则显示周围地雷数,将处理过的格子做标记。如果处理完所有的格 子吗
10、,则游戏胜利,显示胜利信息。b.如果单击鼠标右键,该格子没有红旗则显示红旗。如果有红旗,再击右键,则红旗消失c重复步骤b直到按键结束游戏I. int MineStatistics(int i,int j)统计每个格子周围的地雷数,分别考虑各自处于四个角,四条边以及 中间某个位置的情况。周围是上,下,左,右,左上,左下,右上,右下。在统 计四个角格子周围的地雷数目时,统计其周围的三个方格内是否有地雷,如统计左上角位置周围的地雷数目时,其周围的三个方格的二维坐标依次为( i, j+1), (i+1, j), (i+1, j+1)(设该位置坐标为(i, j)。而统计四条边上某一空格周围 的地雷数目时
11、,则统计其周围的五个方格是否有地雷,如统计左边的边上某位置的地雷数目时,其周围的五个方格的二维坐标依次为(i-1, j), (i-1, j+1), (i, j+1), (i+1,j), (i+1,j+1)(设该位置坐标为(i, j)。而统计普通位置时要统计其 周围的九个方格内是否有地雷,则该点周围的九个坐标依次为(i-1, j-1), (i-1, j), (i-1, j+1), (i, j-1), (i, j+1), (i+1, j-1), (i+1, j-1), (i+1, j), (i+1,j+1). 统计完成后,将统计结果存入对应的结构体的roundnum变量中去。2.图形处理部分A.
12、void Init()对计算机进行图形模式初始化,加载图形驱动包B. void DrawSmile()画一个笑脸C void DrawRedFlag(int i,int j)画一个红旗D. void DrawEmpty(int i,int j,int mode,int color) 画两种空格E void Close()关闭图形模式制t殁济3.鼠标处理部分A. void MouseOn()鼠标显示B. void MouseOff()鼠标隐藏C. void MouseSetXY(int x,int y)设置鼠标当前位置D. int LeftPress() 鼠标左键按下Ei. int RightP
13、ress() 鼠标右键按下F. void MouseGetXY() 得到鼠标当前位置僚售设计五调试与测试1 .书写标识符时,忽略了大小写字母的区别编译程序把i和I认为是两个不同的变量名,而显示出错信息。 C语言认为 大写字母和小写字母是两个不同的字符。 习惯上,符号常量名用大写,变量名用 小写表示,以增加可读性。2 .在程序嵌套比较多时,容易出错在程序嵌套比较多时,很容易多卸“ ”,或者少写“",造成编译错误,为 减少类似错误出现,在写程序时应该采取缩进式写法,让处于同一层次的函数处 于同一条线上,这样就能够减少上述错误的出线3 . win7不支持C语言图形全屏模式,图形处理须加载图
14、形驱动在进行图形部分处理时 win7不支持c语言图形的全屏模式,在XP系统下, 也没法正确运行。原因是 C语言在进行图形处理必须正确设置图形驱动器和模 式,通过函数detectgraphics能自动进行计算机硬件检测,后再进行初始华即可。LI4 .布雷随机数生成的错误以及优化在进行布雷函数编写时,首先用随机数生成函数使随机数生成范围在 (0-1) 之间,使得地雷主要分布与上部,下部区域基本没有地雷,为了使得雷区较为平 均,我又加了一重循环,强制每行最多只能分布2个地雷,并另为生成两个随机 数,强制是随机数的行数,该行不分布地雷,这样使得雷区相对平均,但语句过 于繁琐,且对于知道该布雷规则的人,
15、游戏更加容易,最后我们采用了加大随机 数生成范围,让随机数在(0, t)之间,t可以调节就是得雷区均匀的同时,可 以通过调节t的值来控制某局地雷数目的多少。而在进行生成随机数时时间种子 的生成位置会影响随机数的生成,因为在计算机中随机数一旦生成,计算机就不 会再生成随机数,会导致生成的随机数相同。5在调用递归函数及递归函数编写时的错误在调用递归函数前应该先调用MineStatistics函数统计该格子周围是否无雷,只有当该格子无雷且周围无雷时(而不时该格子处无雷即可),才能调用递归函数向八个方向递归展开无雷区域, 该递归函数的出口是碰到了已经处理过的 格子或者该格子已经做了标记,又或者是该格子
16、有雷,而在进行递归在向周围的 八个方向展开时要注意设置边界值的情况,否则会造成处理数据超出数组定义的边界,造成不必要的错误6 . MineStatistics函数编写时条件不易设置函数MineStatistics编写时不同情况进行分别统计时条件设置很容易错误, 类似于鞍点查找时的错误,导致一类点周围的雷数的统计出现错误,最后我采用在纸上画出模型,在进行某类点周围雷数统计编写时,根据纸上模型的规律进行 编写7 .输赢判断是靠检索非雷的格子是否处理完游戏的输赢判断有两种思路,一是检索是雷的格子是否已经全部做处理 (即 标红旗),二是检索非雷的格子是否已经全部处理完全。雷的数目虽然较少,但 是雷点具
17、有不确定性,为了实现方法一的判断,还需定义一个二维数组,用于保 存哪些位置是有地雷分布的,在进行判断时,首先读取该数组的标记,若该格子 有雷,再从结构体数组中读取flag的值,看该格子的地雷是否已经做了处理。 而, 进行方法二的实现只需要每处理一个非雷的格子,让统计非雷数目的数据自减 一,当其自减为0时,则表示玩家取得了胜利,比较两种处理方法,知道方法二 比较容易实现P f , . V 8.该函数鼠标的光标没法显示出来该函数鼠标的光标没法显示出来,在查询了有关鼠标光标显示后,进行了 鼠标光标显示的尝试。但出现了光标只有在鼠标单击后才能显示,通过条件设置 使得能在移动时显示鼠标的位置, 但鼠标光
18、标的图形会遮盖原有图形的显示。 该 进方法有两种,一是每次进行鼠标显示后进行清屏处理, 但这样需要在清屏前保存所有位置点的信息,数据的保存,读取较复杂,没有实现;二是,在每次进行 鼠标光标输出前通过数据记录改点的图形信息, 在输出鼠标,且鼠标移出改点后, 用原来的图形信息通过图形输出覆盖掉鼠标光标显示留下的痕迹还原原有图形, 该方法的实现也较为复杂,亦没有实现。由于该部分功能没有实现,没有将本部 分相关的代码附录出来六附录#include<>#include<>#include<>#include<>#define LEFTPRESS 0xff0
19、1#define LEFTCLICK 0xff10#define LEFTDRAG 0xff19#define MOUSEMOVE 0xff08void Init();void Close();void DrawSmile();void DrawRedFlag(int i,int j);void DrawEmpty(int i,int j,int mode,int color);void Control。;int MineStatistics(int i,int j);void SpreadMine(int t);void ShowWhite(int i,int j);void GamePla
20、y();void GameBegain();void GameWin();void GameOver();void MouseOn();void MouseOff();void MouseSetXY(int x,int y);int LeftPress();int RightPress();void MouseGetXY();char randminenum3;int minenum;int MouseX,MouseY;int gameAgain=0;int gamePlay=0;structint num;int roundnum;围九个方格内的雷数*/int flag;0*/Mine101
21、0;main()Init();Control。;Close(); getch();/*无雷标0,有雷标1*/*此位置有雷标0,否则统计周/*标记为雷时为1,没有标记为void MouseOn()_AX=0x01;geninterrupt(0x33);/*鼠标光标显示*/void MouseOff()/*鼠标光标隐藏*/_AX=0x02;.geninterrupt(0x33);void MouseSetXY(int x,int y)|* 现jt鼠标当前位置 */_CX=x;_DX=y;_AX=0x04;geninterrupt(0x33);int LeftPress() /*鼠标左键按下*/_A
22、X=0x03;geninterrupt(0x33);return(_BX&1);/*鼠标右键按下*/*得到当前位置*/int RightPress()_AX=0x03;geninterrupt(0x33);return(_BX&2);void MouseGetXY()_AX=0x03;geninterrupt(0x33);MouseX=_CX;MouseY=_DX;.void Init()/*图形初始化*/int gdriver, gmode;registerbgidriver(EGAVGA_driver); /* 加载图形驱动包 */detectgraph(& gdr
23、iver, &gmode); /*检测硬件确定图形驱动程序和模 式*/initgraph(&gdriver, &gmode, "");/* 初始化图形系统,gdriver 和 gmode分别表示图形驱动器和模式,”内为图形驱动的路径*/void DrawSmile()/* 花笑脸 */setfillstyle(SOLID_FILL,YELLOW); /*设置填充模式和颜色,表式对下面所 画图形的填充,此处表示癖下面椭圆的填充(*/JU|r 削ellipse(290,75,10,10);/*画椭圆,前两个参数表示中心点坐标,后面依次为一个宽度和一个高度
24、*/setcolor(YELLOW);置画笔颜色*/setfillstyle(SOLID_FILL,BLACK);/*此处表示对下面两个椭圆的填充*/fillellipse(285,75,2,2);fillellipse(295,75,2,2);setcolor(BLACK);bar(287,80,293,81);/* 画一个二维线条 */void DrawRedFlag(int i,int j)setcolor;/*设置画笔颜色*/setfillstyle(SOLID_FILL,RED);bar(198+j*20,95+i*20,198+j*20+5,95+i*20+5);setcolor(
25、BLACK);line(198+j*20,95+20*i,198+j*20,95+i*20+5);void DrawEmpty(int i,int j,int mode,int color)setcolor(color);sefillstyle(SOLID_FILL,color);if(mode=0)/*没有单击过显示大格子*/bar(200+j*20-8,100+i*20-8,200+j*20+8,100+i*20+8);if(mode=1)/*单击过后显示小格子*/bar(200+j*20-7,100+i*20-7,200+j*20+7,100+i*20+7);void Close()cl
26、osegraph();void SpreadMine(int t)int i,j;minenum=0;srand(int)time(0);/* 生成时间种子 */for(i=0;i<10;i+)for(j=0;j<10;j+)JIuS Mineij.num=rand()%t;if(Mineij.num=1)1minenum+;jfJL ,elseMineij.num=2;Mineij.flag=0;sprintf(randminenum,"%d", minenum);setcolor(1);settextstyle(0,0,2);outtextxy(210,70
27、,randminenum);minenum=100-minenum;/*变量取空白格数量*/MouseOn(); void GameOver()int i,j;setcolor(0);for(i=0;i<10;i+)for(j=0;j<10;j+)if(Mineij.num=1)DrawEmpty(i,j,0,RED);setfillstyle(SOLID_FILL,BLACK);fillellipse(200+j*20,100+i*20,7,7);void GameWin() setcolor(1);settextstyle(0,0,2);outtextxy(230,30,&qu
28、ot;You Win");int MineStatistics(int i,int j)int nNUM=0;if(i=0&&j=0)if(Mine01.num=1) nNUM+;if(Mine10.num=1) nNUM+;if(Mine11.num=1) nNUM+;/*统计左上角*/else if(i=0&&j=9)if(Mine08.num=1) nNUM+;if(Mine19.num=1) nNUM+;if(Mine18.num=1) nNUM+;上角*/else if(i=9&&j=0)if(Mine91.num=1) nN
29、UM+;/*统计左下角*/if(Mine80.num=1) nNUM+;if(Mine81.num=1) nNUM+;)else if(i=9&&j=9)(if(Mine98.num=1) nNUM+;if(Mine89.num=1) nNUM+;if(Mine88.num=1) nNUM+;)else if(i=0&&j!=0&&j!=9)(if(Mineij+1.num=1) nNUM+;if(Mineij-1.num=1) nNUM+;if(Minei+1j-1.num=1) nNUM+;if(Minei+1j.num=1) nNUM+;i
30、f(Minei+1j+1.num=1) ,nNUM+;else if(i=9&&j!=0&&j!=9)(if(Mineij+1.num=1) nNUM+;if(Mineij-1.num=1) nNUM+;if(Minei-1j-1.num=1) nNUM+;if(Minei-1j.num=1) nNUM+;if(Minei-1j+1.num=1) nNUM+;)else if(j=0&&i!=0&&i!=9)(if(Minei-1j.num=1) nNUM+;/*统计右下角*/*统计第一行*/*统计最后一行*/*统计第一列*/if
31、(Minei+1j.num=1) nNUM+;if(Mineij+1.num=1) nNUM+;if(Minei-1j+1.num=1) nNUM+;if(Minei+1j+1.num=1) nNUM+;)else if(j=9&&i!=0&&i!=9)(if(Minei-1j.num=1) nNUM+;if(Minei+1j.num=1) nNUM+;if(Mineij-1.num=1) nNUM+;if(Minei-1j-1.num=1) nNUM+;if(Minei+1j-1.num=1) nNUM+;)else/*统计最后一列*/if(Minei-1j-
32、1.num=1)nNUM+;if(Minei-1j.num=1)nNUM+;if(Minei-1j+1.num=1)nNUM+;if(Mineij-1.num=1)nNUM+;if(Mineij+1.num=1)nNUM+;if(Minei+1j-1.num=1) nNUM+;if(Minei+1j.num=1) nNUM+;if(Minei+1j+1.num=1) nNUM+;)return(nNUM);void GameBegain() int i,j; cleardevice(); if(gamePlay!=1) MouseSetXY(290,70);/*鼠标开始位置,并作为初时坐标*/
33、 MouseX=290; MouseY=70; gamePlay=1;/*下次开始鼠标不重新初始化*/ minenum=0; sefillstyle(SOLID_FILL,7); bar(190,60,390,290); for(i=0;i<10;i+) for(j=0;j<10;j+) DrawEmpty(i,j,0,8); setcolor; DrawSmile(); randomize(); SpreadMine(8); void ShowWhite(int i,int j) 、 if(Mineij.flag=1|Mineij.num=0) . /* 如果显小过红旗或者该格
34、处理过久不对该格进行任何处理*/ return; minenum-; if(Mineij.roundnum=0&&Mineij.num!=1) DrawEmpty(i,j,1,7); Mineij.num=0; else if(Mineij.num!=0) DrawEmpty(i,j,0,8); sprintf(randminenum,"%d",Mineij.roundnum); outtextxy(195+j*20,95+i*20,randminenum); Mineij.num=0; return;if(i!=0&&j!=0&&a
35、mp;Mineij.num!=1) ShowWhite(i-1,j-1);if(i!=0&&j!=9&&Mineij.num!=1) ShowWhite(i-1,j+1);if(i!=9&&j!=0&&Mineij.num!=1) ShowWhite(i+1,j-1);if(i!=9&&j!=9&&Mineij.num!=1) ShowWhite(i+1,j+1);if(i!=0&&Mineij.num!=1) ShowWhite(i-1,j);if(i!=9&&Mi
36、neij.num!=1) ShowWhite(i+1,j);if(j!=0&&Mineij.num!=1) ShowWhite(i,j-1);if(j!=9&&Mineij.num!=1) ShowWhite(i,j+1);void Control。/*游戏失败后判断是/*游戏失败后,没有/*游戏开始*/*游戏具体实现*/int gameFlag=1;否重新开始的标志*/while(1) if(gameFlag) 判断出重新开始或者推出游戏就继续GameBegain();GamePlay();if(gameAgain=1) gameAgain=0; continue;MouseOn();gameFlag=0; if(LeftPress()MouseGetXY();/*判断是否重新开始*/if(MouseX>280&&MouseX<300&&MouseY>65&&MouseY<85)gameFlag=1;continue;if(kbhit() break;MouseOff();void GamePlay()int i,j,num;/*num用于接收一个格子周围右多少地雷*/for(i=0;i<10;i+)for(j=0;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 小学阅读课活动方案5篇
- 第一学期三年级科学教学总结
- 五官门诊实习鉴定(3篇)
- 关于远程培训总结范文
- 小学生演讲稿放飞梦想(31篇)
- DB12-1120-2022 钢铁工业大气污染物排放标准
- 浙江省温州市(2024年-2025年小学五年级语文)人教版小升初真题(上学期)试卷及答案
- 高频电路教案第五章
- 高精度预制装配式混凝土建筑构件生产技术要求编制说明
- 2024年广东省深圳市福田区十校联考中考英语质检试卷(3月份)
- 飞利浦16排螺旋CT机操作规程(1)
- 油菜品种田间记载项目与标准
- 渣土车辆驾驶员管理制度
- 德力西系列变频器说明书
- 后疫情时代探索家校共育新模式维护学生心理健康
- 小学美术11-身边的伙伴ppt课件
- 铁合金生产工艺
- 钢结构策划书(范本)
- 焦化厂生产工序及工艺流程图
- 汽车排放控制系统的检修
- (外研版)初中英语语法汇总[新版]
评论
0/150
提交评论