综合程序的开发流程_第1页
综合程序的开发流程_第2页
综合程序的开发流程_第3页
免费预览已结束,剩余18页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、综合程序的开发流程3.3扫雷游戏的设计扫雷游戏的输赢规则为挖开一个含有雷的方块,游戏失败;正确的标记出所有含有雷的方块,游戏胜利。在222我们已经分析出扫雷游戏的目标和主要的功能,即根据输入的信息,执行相应的诸如挖雷、标记雷、标记疑问、自动挖开等功能,以期在尽快的时间内标识出开局时所埋设的所有地雷。但是,这仅仅是程序层次结构中最上层的部分(如图2-7所示):划分的功能比较抽象,需要进一步的精化;与系统实现的其它相关细节还是空白,需要进一步完善,从而逐渐逼近最后的实现。图2-7扫雷系统的顶层层次图现阶段的设计任务是自顶向下逐步求精,具体要完成以下几点:+继续分析已有功能,直到精化出所有子功能,确

2、定出模块间接口;+描述精化后每个模块的处理过程;+确定主要的数据及其数据结构;+确定输入输出数据的内外部形式;界面的设计以下将展示我们是如何进行扫雷游戏的设计的。1)确定游戏的界面。在此我们的设计非常简单,没有Windows应用系统的风格。只在中部显示由小方块组成的雷区,小方块的背景显示为浅灰,表示该方块没有被挖开或标记; 小方块的背景显示为深灰,表示它已经被挖开或标记为“F” “ ?或“* ”当选中一个方块要操作时,它的边框线为红色。 在屏幕的左上方显示游戏是否成功等信息,这也是游戏结果的表现形式。如图 2-8所示。Ydlii win tg-ane:凸 in2:11F止12F-12亍I-z丁

3、111i3211电Z17i-lF4F-5T百TrIFTa-s-IFIf2H31r12叵22F21Ez云23FrI-TFZFrIFFa-T2WF厂I-a-F1亍F-图2-8扫雷游戏的界面2) 决定游戏的输入方式。Windows系统中的扫雷游戏是采用鼠标作为操作手段的,我们对自己实现的系统决定采用键盘,即通过光标的移动来选择操作的小方块,根据所敲击的键值来选择游戏的功能,这样需要定义功能键。下面是我们对键盘功能键的定义:上,下,左,右键用来移动光标的位置;回车或者空格键用来挖开光标当前指向的一个方块; F, f标记当前光标指向的方块有地雷;Q, q在光标指向方块打一个问号,表示可能有地雷; A ,

4、 a自动挖开光标周围的方块;ESC退出游戏。3) 确定主要的数据,这里主要是有关雷区的数据。雷区界面数据# defineROW16/*表示整个雷区的行数*/# defineCOL 16/*表示整个雷区的列数*/*这样可通过光标位置(i,j),i 0,ROW-1, j 0,COL-1来代表雷区中相应的小方块*/# defi neSTARTX50/*表示雷区在屏幕上的起始x坐标*/# defi neSTARTY50/*表示雷区在屏幕上的起始y坐标*/# defi neSIZEX 20/*表示一个方块的长度*/# defi neSIZEY 20/*表示一个方块的宽度*/+ 雷区内部数据int tot

5、alMi ne ;/*整个雷区所含的地雷总数 */int tableROWCOL;/*数组table的每个元素值记录了雷区对应方块是否有雷:1表示有雷,0表示没有雷*/int nu mROWCOL/*数组num的每个元素值记录了雷区对应方块周围有多少个地雷*/int flagROWCOL;/*数组flag的每个元素值记录了雷区对应方块当前的状态*/在整个系统中 tableROWCOL、numROWCOLJ flagROWCOL是最核心的数据, 是雷区的内部表示,游戏的挖雷、标记雷、标记疑问、自动挖开等界面操作,在内部实际上 是对这些数据的操作。+方块(i,j)的状态取值:#defi neUNF

6、LAG0/*表示该方块还没有被打开或者标记#defi neFLAGED1/*标记该方块有地雷*/#defi neQUESTIONS/*表示该方块可能有地雷*/#defi neEXPLOD30/*踩到地雷爆炸了*/#defi neOPEN40/*一个没有地雷的方块被打开*/*/+光标当前位置数据int pi , pj ;/*记录光标的当前位置,初始时光标在(0,0)上*/int di8=-1,-1,0,1,1,1,0,-1;int dj8 =0,1,1,1,0,-1,-1,-1;/*相对于当前方块而言,di8和dj8分别表示了它周围八个方块的行和列坐标偏移量。它们与当前光标坐标配合使用,可表示周

7、围的方块,如(-1+pi,0+pj)表示当前方块的正上方方块的坐标。*/+游戏状态数据int gameRes/*记录游戏结束的结果状态,值为0表示按esc键退出游戏;-1表示游戏失败;gameRes = 1表示游戏胜利。实际为输出数据的内部形式*/+功能键的键值/*上,下,左右键*/#define UP 0x4800#define DOWN 0x5000#define LEFT 0x4b00#define RIGHT 0x4d00/*回车、空格键*/#define ENTER 0x1c0d#define SPACE 0x3920/*F, f */#define UPPERF 0x2146#de

8、fine LOWERF 0x2166/*Q, q*/#define UPPERQ 0x1051#define LOWERQ 0x1071/*A , a*/#define UPPERA 0x1e41#define LOWERA 0x1e61/*ESC*/#define ESC 0x011b/*为了避免书写错误和明确含义,对系统的按键值用符号常量来定义*/4)功能求精实际上,除了图2-7的主要功能外,我们已经得出我们以图形方式显示游戏界面,而在C系统中屏幕的输出默认的方式是文本方式,所以需要首先将显示方式设置为图形方式。所以到目前为止,可以非常容易地确定出程序主控模块的流程如图2-9所示,下面我们

9、从主控模块入手,继续利用逐步求精的方法来设计系统。第一步,写出主程序的基本框架,确定各个内部模块的函数名和参数。int main()in itGraph(); /*图形显示方式初始化 */don ewGame(); /*初始化新游戏,即开局 */int gameRes=0;doint key = getKey();/* 读入操作信息 */if (key = ESC)gameRes = 0; break;switch(key)对其他key值进行判断处理;if (checkWi n()/*判断游戏是否胜利*/gameRes = 1;while(!gameRes);while (!c on firm

10、(gameRes);return 0;图2-9扫雷游戏的主控模块流程可以看出,主控模块为两层循环结构,外层循环是用于控制游戏是否再次进行。内层是对某次游戏操作进行处理,用gameRes作循环判断。gameRes初始值为0。当游戏获胜时值设为1, 游戏失败时值设为-1,当gameRes值不为0时,意味着游戏已有胜负结果,所以可以退 出本次游戏。另外,当按下ESC键时,用break直接跳出了内部循环,这是受限制的GOTO的使用。主控模块的下属模块有:void initGraph()函数:用于将显示器显示方式设置为图形方式。void newGame()函数:开始新的游戏,初始化新的游戏界面及数据。i

11、nt getKey()函数:得到从键盘读入的操作信息。int checkWin()函数:用于判断游戏是否获胜。若返回值为1表示胜利,返回值为 0 表示游戏还没结束。int confirm(int) 函数:用于判断游戏是否重新开始。参数的值来自gameRes,gameRes=O,表示按esc键退出游戏;gameRes = -1,表示踩到地雷,游戏失败; gameRes = 1,表示游戏胜利。 Confirm 的返回值为 0 表示重新开始游戏;为 1 表示 关闭游戏,退出程序。第二步,对“图形初始化”进一步求精,实现图形显示方式的初始化。void initGraph( )int gdriver =

12、 DETECT, gmode, errorcode; /* request auto detection*/ initgraph(&gdriver, &gmode, f:borlandcbgi); /*nitialize graphics mode*/ errorcode = graphresult();/* read result of initialization*/if (errorcode != grOk) /* an error occurred */printf(Graphics error: %sn, grapherrormsg(errorcode);printf(Press a

13、ny key to halt:);getch();exit(1);/*return with error code */这里的 initgraph() , graphresult() , grapherrormsg() 函数是在 graphics.h 中声明的库函 数,其中 initgraph() 初始化图形硬件,用于设置计算机图形方式;graphresult() 用来判断是否完成了图形的初始化;grapherrormsg()返回出错信息。第三步,对“初始化新游戏”进一步求精。void newGame()cleardevice();generateMine(); /* 随机生成雷区地雷分布 *

14、/pi = pj = 0;drawTable(); /*实现在屏幕上画出雷区 */新的一轮游戏开始时,必须清理掉上次的结果,通过graphics.h中的cleardevice()清除屏幕上已有的显示,通过generateMine()函数随机生成新的雷区地雷分布,即重新设置totalMine、num、table和flag。最后通过drawTable()在屏幕上显示新的游戏界面。generateMine() 的继续细化:void generateMine() 功能:随机生成地雷的分布。参数 : 无 返回值:无 算法描述:1. 计算将要生成的地雷的总数,存放在变量 totalMine 中。2. 将t

15、able数组和num数组清零,table和num都是全局的二维数组,table记录 坐标(x,y)中是否有地雷,0表示没有地雷,1表示有。num 数组表示和 (x,y) 相邻的所有小方块中有多少颗地雷。3. 随机生成 totalMine 个地雷的坐标,动态更新 table 和 num 数组的状态,drawTable() 的继续细化:void drawTable()int i,j;for(i=0;iROW;i+)for(j=0;j0,然后调用drawBlock()函数重新画光标原来所指的方块和现在所指 的方块。其余函数的实现类似,要注意边界条件的判断。函数moveDown() ,当前光标 (pi

16、,pj) 下移一格操作;函数 moveLeft(),当前光标(pi,pj)左移一格操作; 函数moveRight(),当前光 标(pi,pj)右移一格操作。当 key 值为 LOWERF 或 UPPERF 时,执行 flagBlock(pi,pj) 操作。函数 flagBlock(i, j) 标 记光标所指的方块(i,j)有地雷。函数实现过程如下:如果方块的 flag 值为 FLAGED ,则将 flag 值设为 UNFLAG ;如果方块的 flag 值为 UNFLAG ,则将 flag 值设为 FLAGED 。接着调用 drawBlock() 函数重新画这个方块。当 key 值为 LOWER

17、A 或 UPPERA 时,执行 gameRes= autoOpen(pi,pj) 操作。函数 autoOpen(i, j)表示如果某个已经打开了的小方块显示的数字等于它周围已经被标记为雷的 小方块的数目,则表明周围没有被挖开的小方块都已经不是地雷的,自动挖开这些小方块。参数: i 表示坐标的行的值, j 表示坐标的列的值。返回:整型。自动挖开的过程中由于玩家的标记有错误导致挖开了一个雷使得游戏失败, 返回 1,否则返回 0。函数实现过程如下:a) 判断当前的方块是否被挖开。若没有,自动挖开无效,返回0;若是,接( b)。b) 计算当前方块周围被标记为 FLAGED 的方块数目。若该数目等于当前

18、方块的numij 值,对 (i,j) 小方块的八个邻居中所有没有被挖开的小方块调用openMine函数。如果自动挖开过程中踩到地雷,返回 1;否则,返回 0 值。当 key 值为 LOWERQ 或 UPPERQ 时,执行 questBlock(pi,pj) 操作。 函数 questBlock(i, j) 在光标所指向的方块(i,j)上打一个问号,表示可能有地雷。函数实现过程:如果方块的flag值为QUESTION,则将flag值设为UNFLAG ;如果方块的flag值为 UNFLAG,则将flag值设为 QUESTION。接着调用 drawBlock()函数重新画这个方块。第五步,对判断游戏是

19、否胜利进一步求精。int checkWin()功能:判断当前玩家是否已经取胜(即所有没有雷的坐标都已经被挖开了)。参数:无返回值: 整型值, 1表示玩家取得了胜利, 0表示没有。算法描述:对每个没有地雷的坐标,判断该坐标是否已经被挖开,如果遇到有一个没有挖开,返回 0;相反,如果所有没有地雷的坐标都已经被挖开返回1 。4. 编码编码就是用高级语言表示设计阶段产生的算法。在编码阶段,可以使我们再次体会到 使用结构化程序设计技术的主要优点有: 用先全局后局部、 先整体后细节、 先抽象后具体的 逐步求精过程开发出的程序有清晰的层次结构,容易阅读和理解;不使用 GOTO 语句仅使 用单入口单出口的控制

20、结构, 使得程序的静态结构和它的动态执行情况比较一致, 容易保证 程序开发时的正确性和易纠错性; 控制结构有确定的逻辑模式, 编写程序代码只限于使用很 少几种直截了当的方式, 使程序易测试; 程序清晰和模块化使得在修改和重新设计一个软件 时可以重用的代码量最大等。 因此, 结构化程序设计技术能够保证我们得到结构化程序。这种程序便于编写、阅读、修改和维护。这就减少了程序出错的机会,提高了程序的可靠性, 保证了程序的质量。这一小节我们不再赘述 C 语言的基本知识,而是讲述在大型程序编码时应注意的几个 问题。4.1 全局变量在第一章我们已经提到当一个程序较大时,可将一个程序的源代码组织在几个源文件

21、中,每个源文件的内容往往围绕某一功能,或者从某个角度密切相关,如 节扫雷游 戏的 miner.c 文件就是将处理游戏操作的几个模块及其密切相关的图形显示模块放在了一 起。这些源文件是通过函数以及全局变量联系起来的全局变量的作用是增加了函数间数据联系的渠道。通过加 extern 声明,还可将分布在 不同文件中的内容联系起来。 但是全局变量使函数的通用性降低了, 因为函数在执行时要依 赖于其所在的全局变量。 如果将一个函数移到另一个文件中, 还要将有关的全局变量及其值 一起移过去。 但若该全局变量与其它文件的全局变量同名时, 就会出现问题, 降低了程序的 可靠性和通用性。 在程序设计中, 在划分模

22、块时要求模块的 “内聚性” 强、与其它模块的 “耦 合性” 弱。即模块的功能要单一,与其它模块的相互影响要尽量少,而用全局变量是不符合 这个原则的。一般要求把 C 程序中的函数作成一个封闭体,除了可以通过“实参-形参”的渠道与外界发生联系外,没有其它渠道。这样的程序移植性性好,可读性强。另外使用全局变量过多,会降低程序的清晰性,人们往往难以清楚地判断出每个瞬时 各个全局变量的值。在各个函数执行时都可能改变全局变量的值,程序容易出错。对于大型程序,模块多,常常由不同的人来完成不同的模块,如果全局变量的随意使 用,更容易出现问题,造成程序的混乱。因此,更应该限制使用全局变量。在扫雷游戏的实现( )

23、中,我们将主要数据中的 totalMine , gamRes 定义为局部 变量, tableROWCOL 、numROWCOL、flagROWCOL 、di8 、 di8 、pi 和 pj 定义 为全局变量, 这些全局变量的使用虽然简化了函数的实现, 但也影响了它们的通用性。 同学 可做为练习, 将这些全局变量改为局部变量, 来实现扫雷游戏, 以更好的体会全局变量的使 用。4.2 函数“工欲善其事,必先利其器” 。我们在编写大型程序时,要善于利用已有的函数,以减 少重复编写程序段的工作量。已有的函数包括 C 系统提供的大量标准函数(即库函数) ,以 及用户本人或其他人编写的有用的函数。虽然有一

24、些基本的函数是共同的,但不同的 C 系 统提供的库函数的数量和功能还是有所不同。 使用者在使用时应随时查阅系统手册。 本书附 录 A 中列出了 TC2.0 的库函数清单,按照字符函数和字符串函数、数学函数、输入输出函 数、日期和时间函数、动态地址分配、字符屏幕和图形功能函数以及其它函数进行分类,对 每一个函数指明了声明它的 .h 文件、 函数原型、 重要参数的取值说明和功能描述。 在 节扫雷游戏的设计和 节扫雷游戏的编码中,可以看到一些库函数的使用。而且,在 第三章介绍高级编程技术时, 我们又将接触到一些重要的库函数的应用。 善于使用函数或者 可以说某种“模式” ,会使你编程事半功倍。4.3

25、风格写好一个程序,当然需要使它符合语法规则、修正其中的错误和使它运行得足够快, 但是实际应该做的远比这多得多。 程序不仅需要给计算机读, 也要给程序员读。 一个写得好 的程序比那些写得差的程序更容易读、 更容易修改。 经过了如何写好程序的训练, 生产的代 码更可能是正确的。风格的作用主要就是使代码容易读,无论是对程序员本人,还是对其他人。程序设计 风格的原则根源于由实际经验中得到的常识, 它不是随意的规则或者处方。 代码应该是清楚 的和简单的,具有直截了当的逻辑、 自然的表达式、通行的语言使用方式、 有意义的名字和 有帮助作用的注释等, 应该避免耍小聪明的花招, 不使用非正规的结构。 一致性是

26、非常重要 的东西, 如果大家都坚持同样的风格, 其他人就会发现你的代码很容易刻度, 你也容易读懂 其他人的代码。下面我们将用一些好的和不好的小程序设计例子来说明与风格有关的规则, 因为对处理同样事物的两种方式做比较常常很有启发性。 风格不好的代码段的前面我们将标 出一些问号。1) 名字 一个名字应该是非形式的、简练的、易记忆的,若可能的话,最好是能够拼读的。一个 变量的作用域越大,它的名字所携带的信息就应该越多。 全局变量使用具有说明性的名字, 局部变量用短名字。 全局变量可出现在整个程序的任何地方, 因此其名字应具有足够的说明 性,以便使读者能够记得它们是干什么的。 给每个全局变量声明附一个

27、简短注释也是非常有 帮助的。按常规方式使用的局部变量可采用极短的名字,如循环变量用i,j 作为循环变量,p, q 作为指针, s, t 表示字符串等。比较:? for (theElementIndex=0; theElementIndexnumberOfElements; theElementIndex+)? elementArraytheElementIndex=theElementIndex;和for (i=0; inelems; i+)elemii=i;现实中存在许多命名约定或者本地习惯。常见的如:指针采用以 Ptr 结尾的变量名;全 局变量用大写开头变量名; 常量用完全由大写字母拼写的

28、变量名等等。 命名约定能使代码更 易理解。对于大型程序,选择那些好的、具有说明性的、系统化的名字就更加重要。函数采用动作性的名字。 对返回真或假的函数命名, 应该清楚反映它返回值情况。 比较:? if (checkoctal() 和if(isoctal()2) 表达式和语句 名字的合理选择可以帮助读者理解程序, 同样, 我们也应该以尽可能一目了然的形式写 好表达式和语句。 应该写最清晰的代码, 通过给运算符两边加空格的方式来帮助阅读, 用加 括号的方式排除二义性。 这些都是很琐碎的事情, 但却又是非常有价值的。 用缩行显示程序 的结构 。采用一种一致的缩行风格,是使程序呈现出结构清晰的最省力的

29、方法。比较:? for (n+;n100;fieldn+=0 ); ? *i= 0 ; return(n );或者? for (n+; n 100; fieldn+ = 0 );?;? *i = 0 ;? return( n );和for (n+; n 100; n+);fieldn = 0;*i = 0 ;return( n );使用表达式的自然形式 。否定运算的条件表达式比较难理解,比较:? if (!block_id = un blocks)和if (block_id = actblks) | (block_id unblocks)分解复杂的表达式。 C 有很丰富的表达式语法结构和很丰富

30、的运算符, 因此应该避免将 一大堆东西塞进一个结构中。比较:? *x += (xp=(2*k (n-m) ? ck+1 : dk-);和if (2*k (n-m)*xp = ck+1;else :*xp = dk-;*x += xp;当心副作用 。像 + 这一类运算符具有副作用,它们除了返回一个值外,还将隐含地改 变变量的值。 副作用有时用起来很方便, 但有时也会成为问题, 因为变量的取值操作和更新 操作可能不是同时发生。3) 一致性和习惯用法一致性带来的将是更好的程序。 若程序中的格式很随意, 例如对数组做循环, 一会儿采 用下标变量从下到上的方式, 一会儿又用从上到下的方式; 对字符串一会

31、儿用 strcpy 做复制, 一会儿又用 for 循环做复制等等。这些变化就会使人很难看清实际上到底是怎么回事。而如 果相同计算的每次出现总是采用同样方式, 任何变化就预示着是经过了深思熟虑, 要求读者使用一致的缩排和加括号风格 。什么样的缩排风格最好呢?是把化括号放在 if 的同一 行,还是放在下面一行?实际上, 特定风格远没有一致地使用它们更重要, 应该取一种风格。 花括号也可以消除歧义, 但是在使代码更清晰方面的作用却不那么大, 所以建议在必需的时 候使用它。为了一致性,使用习惯用法。 常见习惯用法之一是循环的形式。比较:? i = 0;? while (i =n-1)? arrayi+

32、 = 1.0;或者? for (i = 0; i=n;)? arrayi = 1.0;和for (i = 0; in; i+)arrayi = 1.0;对无穷循环,我们喜欢用for(;)和while(1),请不要使用其它形式。4) 神秘的数神秘的数包括常数、 数组的大小、字符位置、变换因子以及程序中出现的其它以文字形 式写出的数值。给神秘的数起个名字 用没提供任何指示性信息,。在程序源代码里,一个具有原本形式的数对其本身的重要性或作它们也导致程序难以理解和修改。下面比较的是在24 80的终端屏幕上打印字母频率的直方图程序片段:? fac=lim/20; /*set scale factor*/

33、? if (fac1)? fac=1;? /*gen erate histogram*/? for (i=0,col=0;i27;i+,j+)?col+=3;?k=21-(le ti/fac);?star=(le ti=0) ? :*;?for (j=k;j22;j+)?draw(j,col,star);? ? draw(23,2, ); /*label x axis*/? for (i=A;i=Z;i+)? prin tf(%c ,i);和 #defi ne MINROW 1#define MINCOL 1#defi ne MAXROW 24#defi ne MAXCOL 80#defi n

34、e LABELROW 1#defi ne NLET 26#defi ne HEIGHT MAXROW-4/*top edge*/*left edge*/*bottom edge*/*right edge*/*positi on of labels*/*size of alphabet*/*height of bars*/#defi ne WIDTH (MAXCOL-1)/NLET/*width of bars*/fac=(lim+HEIGHT-1)/HEIGHT; /*set scale factor*/ if (fac1)fac=1;/*ge nerate histogram*/for (i

35、=0,col=0;i27;i+,j+)if (leti=0con ti nue;for (j=HEIGHT-le ti/fac;jHEIGHT;j+)draw(j+1+LABELROW,(i+1)*WIDTH,*);draw(MAXROW-1,MAXCOL+1, ); /*label x axis*/for (i=A;i=A & (c)= Z)但如果它在下面的上下文中使用:? while)isupper(c=getchar()?那么, 每当遇到一个大于等于 A 的字符, 程序就会丢掉它, 而下一个字符将被读入并去与 Z 做比较。 因此,上面的实现是错误的。 除了这个问题外, 由于宏是通过文本替

36、换方式实现的, 如果忘记给宏的体和参数加上括号,如:? #define square(x) (x)*(x)? ? 1/square(x)将产生错误,这个宏应该定义为:#define square(x) ( (x)*(x) ) 所以,建议除了定义符号常量外,最好避免使用宏。6) 注释注释是帮助程序读者的一种手段, 它们澄清情况, 不是添乱。注释时要注意:不 要大谈 明显的东西 。注释应该提供那些不能一下子从代码中看到的东西, 或者把那些散布在许多代 码里的信息收集到一起, 否则没有价值。 要给函数和全局数据加注释 。对于函数、 全局变量、 常数定义、 结构的成员等, 以及任何其它加上简短说明就能

37、够帮助理解的内容, 都应该为之 提供注释。 不要与代码矛盾 ,这往往是修改代码后没有对相关注释进行更改造成的。 应该注 释所有不寻常的或者可能迷惑人的内容。 但是如果注释的长度超过了代码本身, 可能就说明 这个代码应该修改了。 所以不要注释差的代码, 重写它 。我们应该尽可能地把代码写的容易 理解,在这方面做得越好,需要写的注释就越少。好的代码需要的注释远远小于差的代码。以上从 6 谈论了程序设计风格, 这里最关键的结论是: 好风格应该成为一种习惯。 如果 你在开始写代码时就关心风格问题, 如何你花时间去审视和改进它, 你将会逐渐养成一种好 的编程习惯。 一旦这种习惯变成自动的东西, 你的潜意

38、识就会帮你照料许多细节问题, 甚至 在以后的工作压力下写出的代码也会更好。4.4 扫雷游戏的源程序扫雷游戏的源程序分为三个文件:ma in .c、miner.c和key.c,其中ma in .c的内容为主控程序,key.c中包含获取输入信息的函数以及功能键的键值,miner.c中将初始化部分、界面绘制的部分、信息处理部分以及相关的数据集中在一起。/*main.c*/#include minerkey.c#include minerminer.cint main()int gameRes;initGraph();begin:newGame();gameRes=0;/*main loop deal

39、ing with keystroke messages*/doint key = getKey();if(key = ESC) break;switch(key)case ENTER: case SPACE: gameRes = openMine(pi,pj);break;case UP: moveUp();break;case DOWN: moveDown();break;case LEFT: moveLeft();break;case RIGHT: moveRight();break;case LOWERF: case UPPERF: flagBlock(pi,pj);break;case

40、 LOWERA: case UPPERA: gameRes = autoOpen(pi,pj);break;case LOWERQ:case UPPERQ: questBlock(pi,pj);break;if(checkWin() gameRes = 1;while(!gameRes);if(!confirm(gameRes) goto begin;return 0;/*End of main.c*/*key.c*/#include /*define key-value*/#define ENTER 0x1c0d#define UP 0x4800#define DOWN 0x5000#def

41、ine LEFT 0x4b00#define RIGHT 0x4d00#define ESC 0x011b #define SPACE 0x3920#define LOWERF 0x2166 #define UPPERF 0x2146#define LOWERA 0x1e61 #define UPPERA 0x1e41#define LOWERQ 0x1071 #define UPPERQ 0x1051int getKey(void) while(1)int key=bioskey(0); switch(key) case ENTER: case UP: case DOWN: case LEF

42、T: case RIGHT: case ESC: case SPACE: case LOWERF: case UPPERF: case LOWERA: case UPPERA: case LOWERQ: case UPPERQ: return key; /*End of key.c*/*miner.c*/#include #include #include #include #define ROW 16 #define COL 16 #define STARTX 50#define STARTY 50#define SIZEX 20#define SIZEY 20#define UNFLAG 0 /*block not flaged*/#define FLAGED 1 /*block that is flaged to be have mine*/#define QUESTION 20 /*not sure*/#define EXPLOD 30#define OPEN 40/*a block which is checked to have no mine*/ int tableROWCOL;int numROWCOL;int flagROWCOL;int pi,pj;int di8=-1,-1,0,1,1,1,0,-1;int dj8=0,1

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论