黑白台扫雷游戏的实现
分析/设计:
1 功能:用黑白台控制游戏的开始和结束
可以通过菜单决定是否开始游戏 默认是10个雷(简单版本),要求可以改变了,雷的个数和雷盘大小 排查某个位置是否有雷:若有雷,择则被炸死,游戏结束 若没有雷,则在这个位置打印周围雷的个数 当最后一个安全位置被找到时,游戏通关2设计:
<1>: 雷盘设计为9*9形式(简单版本),由于依赖于C语言的黑白台实现游戏,因此我们用一个二维数组来充当雷盘,我把这个数组名字记为lei.
<2>:扫雷游戏中的雷我们怎么表示呢?这时候我们想到C语言中用1和0表示真和假,因此我们用1表示某个位置有雷(二维数组的某个元素是雷),0表示这个位置没有雷。
<3>:我们知道,在扫雷游戏中,每找到一个安全位置,屏幕就会刷新一次,打印出已经排查后的雷盘,上面会在安全位置打印出这个位置周围雷的个数,未知位置保持不变。为了方便理解和操作,我们再引入一个二维数组,用来存放排查后的雷盘信息,记这个二维数组的名字为saolei。
<4>;为了区分某个位置是否被排查过,我们将第二个二维数组的元素全部初始化为井号#,某个元素是#表示这个位置还没有被排查。当排查的位置不是雷时,我们统计这个位置周围雷的个数,并把雷的个数放到saolei数组中的对应位置(元素)。
<5>:由于saolei数组的元素初始化为#,而#为字符,那么二维数组saolei就是一个字符数组,为了方便对saolei和lei数组进行操作,我们把lei数组也定义为字符数组,那么用来表示是否有雷的数字1和0就变成了字符1和0。
<6>:在统计某个位置周围雷的个数时,如果这个位置是在雷盘的最外围的话,我们统计起来就比较麻烦,因为我们要避免越界。为此,我们不妨在定义时把二维数组的行列数都加二,这样我们就可以用一种方法统计棋盘各个位置周围的雷的个数。
<7>:我们如何做到随机布置雷呢?这时我们想到C语言中的rand函数,利用rand函数生成随机数,把随机数作为雷的坐标,但是rand函数生产随机书=数依赖于种子,为了避免rand生成伪随机数,我们引入srand函数和time函数,确保每次游戏运行时布置的雷是随机的。
下面开始写代码
在之前学习static和extern时学习了多文件的形式对函数的声明和定义,正好在此实践一下,设计三个文件:
teas.c //用于存放主函数main及对其余代码测试
game.c //用于实现自定义函数的功能
game.h //声明自定义函数
为了方便更改雷的个数和棋盘大小,我们使用宏定义常量,定义四个常量:1,row //表示棋盘行数
2,col //表示棋盘列数
3,rows //棋盘行数加2
4,cols //棋盘列数加2
我们将宏定义放到头文件game.h中,同时为了主文件test.c和game.c头文件重复包含,我们将需要的头文件放到game.h中,在test.c和game.h中包含game.h这个头文件即可
game.h
在这里插入代码片#pragmaonce#include<stdio.h>#include<stdlib.h>#include<time.h>#definerow9#definecol9#definerows(row+2)#definecols(col+2)#defineeasycount79//初始化雷盘voidchusigame(chars[rows][cols],intr,intc,charch);//打印雷盘voidshows(chars[rows][cols],inti,intj);//布置雷voidsetlei(chars[rows][cols]);//扫雷voidfindlei(chars1[rows][cols],chars2[rows][cols]);game.c
在这里插入代码片#define_CRT_SECURE_NO_WARNINGS#include"game.h"//初始化雷盘voidchusigame(chars[rows][cols],intr,intc,charch){inti=0;for(i=0;i<r;i++){for(intj=0;j<c;j++){s[i][j]=ch;}}}//打印雷盘voidshows(chars[rows][cols],intr,intc){inti=0;intj=0;printf("注:第一行是列标,第一列是行标,其余的是雷盘\n");for(i=0;i<=r;i++)printf("%d ",i);//打印列标printf("\n");for(i=1;i<=r;i++){printf("%d ",i);//打印行标for(j=1;j<=c;j++){printf("%c ",s[i][j]);}printf("\n");}}//布置雷voidsetlei(chars[rows][cols]){intx=0;inty=0;intcount=easycount;while(count){x=rand()%9+1;y=rand()%9+1;if(s[x][y]=='0')//先判断这个位置是否布置过雷了,如果没有再布置{s[x][y]='1';count--;}}}intcountlei(chars[rows][cols],intx,inty){intcount=0;inti=0;intj=0;for(i=-1;i<=1;i++){for(j=-1;j<=1;j++){count+=s[x+i][y+j]-'0';//减去'0'的目的是把表示雷的信息的字符‘1’‘0’转化为数字1和0//这样相加后的结果就是lei[x][y]周围雷的个数}}returncount;}//扫雷voidfindlei(chars1[rows][cols],chars2[rows][cols]){intcount=0;//统计已经排查出的安全位置printf("请输入要排查的坐标(输入样例:3 5,其中两数字用空格隔开),横坐标范围:1-%d,纵坐标范围:1-%d\n",row,col);while(1){intx=0;inty=0;scanf("%d %d",&x,&y);//先检查输入的坐标是否正确if(x>=1&&x<=row&&y>=1&&y<=cols){if(s1[x][y]=='1'){printf("很遗憾,你被炸死了,下面是雷的分布情况\n");shows(s1,row,col);break;}else{if(s2[x][y]=='*')//s2[x][y]==‘*’说明这个位置没有排查过{count++;printf("恭喜你,这个位置没有雷,下面是已排查出的雷的信息\n");//统计坐标x,y附近雷的个数,并赋值给s2[x][y]s2[x][y]=countlei(s1,x,y)+'0';shows(s2,row,col);printf("\n");if(count<row*col-easycount){printf("请继续排雷,输入你要排查的坐标\n");}else{printf("恭喜你,已经排查出了所有的雷\n");break;}}else{printf("此位置已经排查过了,请重新输入坐标\n");}}}else//坐标输入不正确时,重新输入{printf("输入的坐标范围错误,请重新输入\n");}}}test.c
在这里插入代码片#define_CRT_SECURE_NO_WARNINGS//主测试的文件#include"game.h"voidmenu(){printf("请选择是否开始游戏(选择数字即可)\n");printf("********************\n");printf("*****1:开始游戏*****\n");printf("*****0:退出游戏*****\n");printf("********************\n");}voidgame(){printf("扫雷开始\n");//定义两个数组charlei[rows][cols];//存放布置的雷的信息charsaolei[rows][cols];//初始化雷盘chusigame(lei,rows,cols,'0');chusigame(saolei,rows,cols,'*');//打印初始化的结果//shows(lei, row, col);//printf("排查后的雷盘为:\n");//shows(saolei, row, col);//布置雷setlei(lei);//shows(lei, row, col);//打印出来看看是否布置成功//开始扫雷findlei(lei,saolei);}intmain(){srand((unsignedint)time(NULL));//先选择玩不玩,至少选择一次,用do-while循环intchoice=0;do{menu();//游戏菜单scanf("%d",&choice);switch(choice){case0:printf("游戏结束");break;case1:printf("游戏开始\n");game();//游戏主体break;default:printf("选择错误,请重新选择");break;}}while(choice);return0;}以上代码或者别的地方有错误或者不当之处,还请指出,我会不断改进!