C语言扫雷游戏代码学习笔记(一):9*9简单模式

学习了数组和函数,可以用数组与函数实现扫雷代码。我先尝试9*9的扫雷代码。代码要求:

1.布置10个雷

2.点到有雷的格子,游戏结束。

3.点到没有雷的格子,显示周围有几个雷。

4.点开所有不带雷的格子,(也就是除了10个雷,剩下的都点开了),扫雷成功。

第一步,创建test.c文件

       test.c里面写main函数。main函数里写的是扫雷游戏的运行逻辑,就是选择1开始游戏,选择0结束游戏,选择其他数字,显示输入错误,重新选择(需要用到do while循环,因为代码运行起来的时候会先执行一次“请选择1或者0”,再根据输入的数字做循环的判断,所以用do while循环比较方便”)。

        测试成功,do while 循环在input是0时,结束循环,循环结束了,游戏会往下执行return0,结束程序;当输入1或者其他错误数值(如11,3,101等),因为此时的input不是0,所以仍会执行循环,回到循环开始的第10行,再次执行printf("请输入数字1或者0:")。

        可以给main函数加个游戏菜单,装饰一下,写一个菜单menu()函数。menu函数放到do while循环开头,游戏运行时先打印出来菜单。

    接下来 写一个game()函数,这个函数要创建一个二维数组int mine[9][9](暂时先假设它是int数组),下标0~8,因为扫雷是9*9的九宫格,用二维数组表示很方便。

        接下来思考扫雷的一些逻辑,首先是里面有10个雷,先随机画个图,放进去10个雷。

        黄色格子里周围一圈是1个雷,显示1;橙色格子同理,显示2;但到了绿色格子会出问题,因为有3个格子跑到数组外面去了,数组的外面放的什么数字,不知道,所以绿色显示的雷个数不一定是1。解决办法是把数组变大,包含住9*9九宫格周围的一圈。所以数组要变成int mine[11][11],下标1~10,内部9*9放雷,把外部一圈设置成0,代表没有雷,雷用1表示(计算机内除了0就是1,这样想比较容易理解),如下图,这样绿色格子里雷的个数就不会出错误了。

      当看到上图的时候还是会感觉有点怪怪的,雷是1来表示,数出来的雷的个数如果是橙色区域的2还好,能区分开,如果是黄色和绿色表示1个雷的个数呢?和表示雷的1无法区分

      我学到的办法是创建第二个int show[11][11]二维数组,承担显示雷个数的功能,第一个二维数组int mine[11][11]只放入雷,之后不要再进行任何操作了。这样2个数组分工明确,第一个是放入雷,并且保持不动,不修改;数出的雷的个数放到第二个数组里,这样就不会混淆了。如下如:

        写代码,创建2个11*11的二维数组。

        数组创建完毕,接下来就要对2个数组进行初始化,1号数组全部放入0,代表没有雷(雷后面再放),2号数组全部放入字符'*','*'代表这个格子还没有被探索两个二维数组都是11*11的,所以写一个初始化数组的InitBoard()函数就行了(2个数组一个全是0,一个全是'*',用一个函数初始化,比较方便,差别在于放入的内容不同)。

        不过此时会出现一个问题,数字1和0是int整型,字符'*'是字符char类型,2个类型不一样,无法公用一套初始化函数。解决办法第一个数组用字符char '0'和字符'1'来代替整型的0和1。所以2个数组要改成char类型,都用字符。

  接下来进行初始化,InitBoard函数后面写。

        第二步,创建game.c文件

        在里面写InitBoard()函数,用来初始化2个二维数组,用for循环嵌套。

      由于InitBoard是在game.c文件里,test.c里的函数想使用,就需要先声明一下,创建头文件game.h,InitBoard函数的声明写在里面,由test.c引用即可。

        test.c引用创建的头文件game.h

        两个二维数组已经创建完毕,接下来就是把2个二维数组打印出来,打印出来,才能玩这个游戏。

        使用函数DisplayBoard(还没写这个函数)来呈现2个二维数组,参数9代表打印布雷的9行9列,周围一圈不用打印。

        接下来写DisplayBoard函数,同样使用for循环嵌套打印。

打印的是11*11内部的9*9九宫格,数组下标是从1到9,所以循环从i=1开始,到i=9,如下图:

同样在game.h写好函数声明

把main函数这里改成game();不然执行不了void game()函数。

开始执行程序

数组初始化成功,打印成功,不过字符挤在一起有点丑,要在DisplayBoard函数%c打印后加个空格

再次测试程序

排版好看了很多。

        把2个数组分开,这样看起来方便

接下来为了方便定位,给数组加上行标志和列标志,先加入行标。

接下来打印列标

看上去一目了然,很美观。

第三步,准备工作做好了,接下来写游戏规则相关的函数

        (一) 先写随机布雷函数

        要求布10个雷,行和列数随机产生,所以需要用到rand()函数来产生随机数。rand()函数随机数范围是0~32767,想产生1~9的随机数要分两步。

        第一步先产生0~8的随机数,用rand()%9,取余数,任何数除以9,余数范围都在0~8。第二步在这个值上面加1就能得到1~9的随机数了。别忘了用与之配套的srand函数来产生随机数的种子。使用rand和srand函数需要头文件<stdlib.h>,使用time函数需要头文件<time.h>,把这2个头文件都放到game.h内,顺便把<stdio.h>也移动到game.h内,集中搬家。

test.c和game.c只需要引用hame.h就可以了。

      先在main函数内,产生srand种子,种子产生一次就足够了,不用进循环重复产生。

       再写一个setmine函数用来布雷。

在game.h内加入函数声明

在test.c文件内的game()函数使用setmine来布雷,我再用一遍Display函数打印2个数组,看看雷的位置。

随机布雷成功,不过我仔细数了一下,好像只有9个雷?缺一个雷,应该是第10个雷和前面的位置重复了,这样需要修改setmine函数。逻辑是:当这个位置不是1(也就是没有雷)的情况下才可以布雷。

数了一下,是10个雷,随机布雷函数书写成功。

        (二)接下来书写排查雷的函数

        在game.c写Findmine函数。函数的逻辑是:

        1.输入坐标,2个1~9的数字

        2.判断这个坐标是不是在9*9的范围内,坐标错误,提醒输入错误,重新输入坐标

        3.坐标输入正确,判断是不是雷,是雷,则游戏结束;不是雷,则显示周围雷的数量

        4.当所以不是雷的格子被探索完毕,游戏胜利。

由于Findmine函数需要重复输入坐标进行探索,所以应当放到循环内,使用while循环

        接下来写坐标正确的情况下的代码,分为踩雷和不踩雷的情况,如果踩雷,跳出循环,如果没踩雷,继续循环

      封装一个GetmineCount函数,专门用来数坐标周围一圈雷的个数,函数有返回值,返回值就是雷的个数。

        GetmineCount函数要把坐标周围8个格子里的值加起来,有几个'1',就输出(返回)数字几。

        但这样的结果是错误的,因为二维数组内部不是int类型的0和1,而是字符char类型的'0'和'1',char类型的值进行加减计算时,用的是对应的ASCII码的值,也就是'0'对应的是十进制数字48,'1'对应的十进制49。因此,想要返回正确的值,需要每个坐标的值减去48,可以写作减去'0',这样才能得到雷的个数,加了8个坐标,减去8个'0',修改GetmineCount函数:

      得到的count值,要送入show[11][11],表现为对应坐标的'*'变成count的值,此时的count要加一个'0',变成字符,才能送入show[11][11],并且将show[11][11]打印出来,顺便也把踩雷后的雷的位置mine[11][11]打印出来让人看看。

        这样函数还是未完成,因为while(1)还是个死循环,即便是点亮全部正确坐标,函数仍然不会结束,所以要给while()加条件,设一个变量win,每点亮一个win就加1,9*9一共81个坐标,其中10个是雷,这样有71个没有雷的坐标,修改Findmine函数:

接下来运行代码,测试下:

程序运行成功,也能探索未知格子,并且能显示周围一圈雷的个数,根据图上信息,坐标(2,2)应该是个雷,测试下:

踩雷了,并且也把mine[11][11]雷的位置都打印出来了,测试成功。

      最后做下程序的完善,注释掉测试用的代码,隐藏mine[11][11](布雷数组不让人看见,只需要显示第二个数组就行)等等。

      完结,撒花~~~

      这个程序限定了二维数组的容量为9*9,如果想要改变扫雷难度,变成16*16,40个雷,要修改好多地方,所以可以在头文件game.h里面定义ROW为9,COL为9,(ROWS为ROW+2,COLS为COL+2),雷的个数COUNT为10,这样只需要修改头文件ROW、COL和COUNT的值,就能调整整个扫雷游戏的难度。

        今天先不完善代码了,以后再说。

        等等,突发奇想,之前学过一个C语言请屏幕的代码,system("cls"),能清除掉全屏幕的内容。这个程序是点亮一个坐标,就打印一次数组,但之前的数组还存在,这样就好像许多个数组不停往下显示,像糖葫芦串。如果用清屏代码system("cls"),会不会输入一个坐标,清掉屏幕,打印数组,让扫雷游戏看上去始终在一个棋盘上?修改代码:

放到scanf之后,意为输入坐标后,清掉之前内容,再去打印下面的数组。

main后面也加上一个,清掉菜单,最后测试下效果:

多次探测,数组始终保持在同一位置,看起来舒服多了

再踩个雷,如上图,推测坐标(3,4)是雷,踩一下

没问题,这局势游戏结束了,输入1继续游戏

又是简洁的屏幕,测试成功。

        今天先到这里了,扫雷代码的完善以后再说。

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值