前言:
在学完二维数组的知识后,我们来应用一下二维数组中的行列思维,敲上三子棋这个小游戏。
1.菜单的打印
和前面讲到的猜数字一样。玩游戏前需要打印一个菜单,让玩游戏的人知道这是个什么游戏,怎么玩,需要玩家做什么等,我们通过封装一个菜单函数来实现。
void menu() { printf("********************\n"); printf("***** 1.play ******\n"); printf("***** 0.exit ******\n"); printf("********************\n"); } int main() { //接收玩家输入的值 int input = 0; menu(); printf("这是一个三字棋游戏,请输入>:"); scanf("%d", &input); return 0; }
这个时候,在控制台打印出来的效果如下:
光标闪烁在等待我们输入值。接下来的一步就是:对玩家输入的值进行相应不同的处理,玩家输入1,进入玩游戏的分支,玩家输入0,退出程序,当然不排除一些调皮捣蛋的玩家,喜欢鼓弄,我们使用default(默认)来应付。
补充:return 0;语句在制定规则的时候,一部分人提出希望程序最后可以省略这句话,最终通过了。当主函数(仅对主函数)结束时,没遇到return 0;语句,则自动使用return 0;返回。相当于有写return 0;但我们最好写上去!
当然,我们不只是每次都选择一次就结束掉程序。比如我玩一把游戏后,还觉得挺好玩,想再来一把,相应的需要把这段代码写成一个循环才能实现。
分析:一运行程序就让我们选择玩还是不玩,如果不玩,选择0就退出游戏,结束循环;如果玩,选择了1,在游戏结束后,再次打印菜单让我们重新选择玩不玩。还有就是输入非法值,我们得重新进行选择,最后直到我们输入0退出循环,结束程序。
在这个过程中,一运行程序,不管什么都让我们选择玩不玩游戏,这是循环里的循环部分,符合这种特性的循环是do while循环,一上来就执行一次循环体;while()判断部分我们仔细一想,在选择的时候,选择0退出游戏,选择1或选择输入非法值的时候重新执行一次循环体。对应到循环,如果判断表达式是0则退出循环,非0(1或非法值)则继续循环,我们可以得出使用input做循环的判断条件最合适了。
这上面相当于是一个模块,我们理解里面的思想(主要是循环用input当判断条件)就没问题了。博主把这部分当成菜单模块。
2.三子棋构思
在写代码之前,需要初步思考实现三子棋需要用什么方式实现。
这个棋子与棋子之间分割线,我们使用循环来控制打印就可以了。然后是玩家下棋,每下一步棋,都会改变数组里的元素,接着是电脑下棋,电脑下棋也是一样会改变数组元素的,到最后直到有一方胜出或平局结束游戏。
通过简单分析,我们需要创建一个三行三列的二维数组,这个数组起初存放的值我们都初始化为空格,因为空格打印出来看不见。接着就是实现玩家下棋的函数、电脑下棋的函数、判断输赢的函数。
3.实现三子棋
3.1使用宏的方式定义数组
函数的声明、头文件的包含,宏的定义都放在.h文件里。.c文件里包含.h文件就可以正常使用.h里定义的标识符以及引用的头文件里的库函数。
3.2打印棋盘
也许对于初学者,打印棋盘是最难消化接收的一个,没事,咱们娓娓道来。
打印数据行
“井”字有三行,二维数组也是有三行。其实棋盘是根据二维数组的大小来变换的。我们来看到数据行,数据行有两部分组成,一部分是:空格+%c+空格,另一部分是|(竖杠)。
相信大家都已经懂数据行的打印了(doge),我们看分割行的部分(---|---|---):
打印分割行
不难发现,打印分割行第的时候,最右边的|还是不需要打印,简直就像是把数据行中,用---替代空格+%c+空格,|还是|一样。
ok,到这里最难的棋盘打印就讲完了,这时候,如果我们改变标识符ROW、COL的值,棋盘的大小也会随之改变。因为我们都是使用row,col做控制的,当然这个循环就有变得性啦~
3.3玩家下棋
下棋就是说,把二维数组里的元素改成玩家用的棋子(字符)就行,这样打印的时候,相当于数组相应位置放了棋子一样。电脑下棋也是同理,既然这样,那我们快点来实现吧。
这里需要提的点是:坐标合法部分为什么是x(1-3),y(1-3)。而且在下棋的时候反而减掉1,这不是没事找事做吗,直接输入(0-2)之间的数不就好了吗?是的,数组的访问下标是从0开始,我们知道是因为我们是程序猿,但玩家不知道呀,把这个游戏放出去,随便拉一个玩家让他输入一个坐标下棋子,玩家想下第一行第一列必定会输入1 1。所以我们程序猿要考虑下用户的习惯,这叫做用户友好,用户并不需要知道程序内部是进行了什么样的操作,根据常识玩游戏就可以了。
3.4电脑随机下棋
我们这里实现的是电脑随机下棋,如果想提升难度,可以对电脑下棋的位置进行更多的操作判断。也就是说,当玩家下了某一个棋子后,电脑不是随机下棋,而是根据棋盘上的情况选择下棋,这个棋子对围堵玩家的棋子有效或是对电脑进一步取胜有效。
我们先看一下test.c文件里的调用接口函数情况吧:
我们说应该是游戏有结果了,也就是人机下棋应该是一个循环,下棋下到能判断输赢还是平局才能退出来。所以应该是这样的~
那么有读者会问了,如何退出这个一直下棋的循环呢?我们使用判断输赢的函数Is_win,玩家下棋后判断游戏是不是结束了(有一方赢了或棋盘满了),电脑下棋后判断游戏是不是结束了,来退出循环。
3.5判断结局
我们应该怎么设计这个判断结局的函数呢?我们知道三子棋要赢的话,横三列、竖三行,两条对角线都是其中一方的棋子的时候,这时就有一方获胜。如果棋盘满了,我们也没有继续的必要了。那么我们如何将某一方获胜或棋盘满了或还没到结局需要继续下棋的状态告诉主调函数(game)呢?我们使用如下的返回值:
某一方赢就返回赢的条件里任意一个位置的棋子(看下面就理解了~)
棋盘没有满,返回字符'C'告诉主调函数说:"继续下棋"
棋盘满了,返回字符'F'说明棋盘满了
我们来看一下主调函数的部分:
再来看实现判断结局部分:
横三列和竖三行:
对角线:
判断满没满的函数:
好啦,这就是三字棋的全部实现啦。都到这份上了,不玩一把很难收场,博主替大家玩一把并把截图放出来证明可行性~
抱歉,图片有点长,哈哈~
其实对于三子棋还有一些改进的地方,比如我们可以设置成五子棋呀;把电脑下棋设智能一点;这些也是可以实现的。还有设置一个图形化游戏界面等等。博主暂且先不研究,后期学有余力再研究写篇博客出来~