由于代码较长,为了增加可读性,我们把代码分别写到game.h,game.c,test.c,里面,其中game.h用来声明函数,实现函数功能的代码在game.c,测试游戏的代码在test.c
为了方便后续的更改,代码使用了宏定义,并没有把棋盘大小写死,这样只要后续要是想要写五子棋甚至n子棋,只需要更改宏定义的数值即可。
下面是game.h中对于所有函数的声明
下面是test.c
仍然是采用的do..while()循环加上switch语句,这与我们前面写过的猜数字游戏类似,上来先打印一个菜单,让输入1或0决定开始游戏还是退出游戏,如果玩一次不过瘾还可以连续玩,直到输入0退出游戏
首先程序运行起来之后不管三七二十一都先打印一个菜单,供玩家选择,当玩家输入1才开始游戏,这时候先初始化棋盘,然后把棋盘打印出来,屏幕上就会呈现一个空棋盘,然后玩家和电脑就可以开始下棋了,由于玩家和电脑都要走很多步才能结束游戏,因此显然是一个循环,循环结束的条件就是有没有一方获得胜利或者平局。
先来看初始化棋盘的函数
我们所谓的棋盘其实就是一个三行三列的二维数组,创建并把这个二维数组中的所有元素均初始化为空格。
再来看打印棋盘的函数
前面我们已经把二维数组的所有内容均初始化为了0,如果我们直接打印,其实是什么也看不到,这样的棋盘对于玩家来讲是非常不友好的,因此我们要打印一个更优美的棋盘,比如这样的
这其实是由一些符号拼起来的一个像棋盘的图案,就是先来一行三空格一竖杠,再来一行三个_一个竖杠,重复多次即可,而且最后一行是不需要竖杠的,最后一列也是不需要___|的,然而这样我们发现最后一行永远都是三空格一竖杠,在形状上显得略微不对称,就像这样
因此我们最后又人为的打印了一行三空格一竖杠,让图形看着更加对称
玩家下棋的函数
由于数组下标是从0开始的,我们要想在第一行第一列下棋1,应该输入坐标是0 0,这显然不符合大众的理解,大众并不知道数组下标是从零开始的,因此我们这里让打印的是arr[x-1][y-1],要考虑到以下几种情况:首先玩家因为我们的棋盘只有三行三列,玩家如果输入一个坐标在第五行,显然是不行的,这时候我们让玩家重新输入,再者就是玩家输入的坐标可能已经被占用了,这时候就提示玩家坐标已被占用,请重新输入,如果上述两种问题均不存在,则在对应的坐标位置放上一个*,当然我们走完之后要紧接着调用打印棋盘的函数打印一下,效果如图:
电脑下棋的函数
为了方便,我们就让电脑随机下棋即可,电脑下棋我们通过模上row和模上col就能产生0~row-1,与0~col-1,有了这样的限制,电脑就不会产生非法坐标了,生成随机数的方式就是rand函数,在调用rand函数之前要调用srand函数,这是rand函数的语法,srand函数用于设置时间戳,且只需要在主函数中调用一次即可,这里有一个设置时间戳的固定方法就是srand((unsigned)time(NULL)),希望读着能够记住这个写法。在以后需要产生随机数的时候均可以直接套用。
电脑下棋虽然不会有非法坐标,但是也会出现坐标已经被占用的情况,这时候我们就让电脑悄悄地再下一次即可。
接下来是判断棋盘是否已经满了的函数
这个逻辑还是非常简单的,我们只要遍历一遍此时的二维数组,看看是否有空格即可,如果一个空格都没有,当然就满了。
最后是判断玩家输赢的函数
假设玩家赢返回*,电脑赢返回#,没有结束返回C,平局返回Q
这样写的好处就是有三点连成一线的时候直接返回其中任意一个坐标处的内容即可,玩家赢,说明有三个*连成了一条线,我们返回其中任意一个就是*,这就与我们前面让玩家赢返回*的逻辑对应上了,电脑赢同理,判断是否平局其实就是看看棋盘是不是已经满了,利用前面的isfull函数即可。
自此所有的函数都写完了,一个简易的三子棋游戏就完成了。效果如图
只要我们不输入0,在一局下完之后会紧接着再打印菜单让玩家选择。