手把手教你制作三子棋!(保姆级)

🎉前言

本篇博客会给大家讲解最简单三子棋的制作,会先给大家介绍整体思路,再逐步实现,会用到较多分支与循环的知识点,如果你已经学习过分支与循环相关的几个关键字,那么这篇博客就是适合你的,希望你看完可以自己写出来属于你的三子棋!!!
在写比较复杂的代码时,我们是分部写的,为了能够正确的写出完整的程序,我们应该分部进行检测,每写一步,我们就进行一次运行,否则整个工程写下来后我们找错误是很费劲的 。

一、结构说明

说明

由于这是一个复杂的程序(对于我这个新人来说这是第一个比较麻烦的代码),我们会采用三个部分进行实现,分别为game.c,game.h,test.c,每一个介绍完先给大家看一下本文件的全部代码,然后逐步讲解,只要你认真看完,一定能学会的!

game.h

game.h里面会声明所有在三个文件中用到的函数(库函数和自定义函数),起到声明的作用。
在这里插入图片描述

test.c

test.c是我们编译器运行的文件,这个文件里会直接应用头文件中声明的函数,所以我们需要包含一下头文件,就可以直接使用各种函数了。
在这里插入图片描述

game.c

这个是最复杂的文件,因为这个文件里的内容是各个自定义函数的定义,也就是说头文件中只声明的自定义函数,需要在本文件中进行定义,因为要用到头文件里的定义的宏(最后总结会说的),所以我们也要包含以下头文件。
在这里插入图片描述
一张不够,所以分成了俩张,他们是连着的。
在这里插入图片描述

二、整理思路

1、打印菜单

我们知道,当我们玩游戏的时候,我们首先会让玩家有一个自己的选择,那就是自己是否要开始游戏,这个时候我们就需要用到游戏菜单。

2、玩家选择

当我们打印出菜单,玩家会进行选择,我们会对应不同的选择给出不同的结果,

3、游戏模板

如果玩家选择了开始游戏,那么我们就要打印出来三子棋的模板。

4、实现下棋

这一步我们需要设计出玩家下棋和电脑下棋,然后轮流循环进行。

5、判定输赢

当我们开始玩游戏后,游戏肯定会结束的,这时候我们需要判定一方胜利或游戏平局。

三、游戏实现

1、打印菜单

这个在我的博客猜数字游戏里已经用到过,比较简单,看一下就能直到其中的思路了:
在这里插入图片描述

2、玩家选择

这个也是和猜数字游戏里一样,只需要用到一个switch循环和do…while循环即可,如图:
在这里插入图片描述
从这里开始,接下来的步骤就是整个游戏的关键了,所以接下来的部分会详细说明。

3、游戏模板

首先我们要打印出来棋盘,在打印棋盘之前,我们需要用到一个二维数组,这是为什么呢?因为我们等会玩游戏需要用到玩家输入几行几列来填充棋子,所以我们先创建一个二维数组,把二维数组与棋盘结合在一起,等我们真正开始下棋的时候,我们实质上就是在二维数组里赋值。那么先给大家看一下棋子的模板,然后自己想一下二维数组是怎么和棋盘结合在一起的,如图:
在这里插入图片描述
相信你已经想出来了,没错,我们下的棋是指就是填充到了二维数组里,如图:
在这里插入图片描述
代码如下:
在这里插入图片描述

解释:这个图分为两个部分,第一部分就是给二维数组初始化(我们已经在test.c里创建了一个未初始化的二维数组,然后在game.c里进行初始化),至于第二部分,我们采取的打印方法是分成很少很少一直打印,但是应该没有更简单的打印方法,因为我们要确保最右边少一个‘|’,最下边少一行,我们只能把他们拆解出来,然后用if语句判断,然后符合条件的打印出来。 目前运行结果如下:
在这里插入图片描述

4、实现下棋

☃️玩家下棋

在这里插入图片描述
解释:

  1. 首先玩家输入位置(因为玩家一般不懂得编程,所以认为第一个就是从一开始的,而事实是从0开始了,为了玩家的可玩性,我们只能自我调整)。
  2. 输入位置后,我们开始判断输入的位置是否合法,不合法的话玩家重新输入
  3. 当位置合法,我们需要判断是否已经重复,所以我们判定该位置数组是否还为空格,如果不是,玩家需要从新下棋。

☃️电脑下棋

在这里插入图片描述

解释:

  • 因为电脑下棋不需要人为干预,所以不用考虑到从1开始(+1)
  • 这里我们运用到了之前猜数字游戏博客中用到的知识:生成随机数的函数rand,这里我用通俗的解释再说明一遍:rand函数生成随机数如果用srand()函数(调用一次就可以一直使用了),srand需要一个种子,播下种子之后,如果种子不变,那么生成的那个随机数不变,所以如果我们想生成一个每时每刻都不一样的随机数,那么就需要我们用到另一个库函数,time函数,time函数是自1970年1月1日0时开始到目前为止的秒数,因为每次运行结果的时间是不相同的,所以自然产生的随机数也就不同。
  • 因此我们常常使用系统时间来初始化,使用time函数来获取系统时间,得到的值是一个时间戳,即从1970年1月1日0点到现在时间的秒数,然后将得到的time_t类型数据转化为(unsigned int)的数,然后再传给srand函数,用法如下:
    srand((unsigned int)time(NULL));//我们在使用rand和srand时,主要使用的就是这一种初始化方法!!
    如果仍然觉得时间间隔太小,可以在(unsigned)time(0)或者(unsigned)time(NULL)后面乘上某个合适的整数。 例如,srand((unsigned)time(NULL)*10),为什么要强制类型转换呢,因为srand想要的类型是无符号整型,而time函数返回值为_time型,所以要强制转换。不需要深究,目前我们知道这些能用就足够了。
    time的参数传NULL表示不需要经过参数获得到的time_t数据,time函数原型如下:
    time_t time(time_t *tloc);//time_t类型被定义为一个长整型

☃️循环

因为是要一直下棋的,所以我们要把他们弄成循环,至于输赢和平局,请接着看下面的讲解。

5、判定输赢

在这里插入图片描述
第一个箭头是验证三个横排的,第二个箭头是验证三个竖排的,第三个箭头是验证从左向右倾斜的那个,第四个箭头是验证从右向左倾斜的那个。验证完这些,我们还需要验证是否为平局,因为平局(is_full)函数只在game.c里用一次,所一没必要在头文件声明了,只用在game.c里创建就可以了。如图:
在这里插入图片描述

解释:我们在验证完没有输赢后再验证时候已经下满,也就是说看数组里是否还有空格,如果有,那么就返回可以继续下棋的命令,否则就返回平局。
此时我们的test.c文件就变成了:
在这里插入图片描述
解释:认真看,你就会发现其中的原理,我们每下一次棋,都会让电脑打印出来棋盘供玩家观看,然后电脑再判断这局是否应该结束(我们用的字符‘0’进行判断,具体时根据is_win函数里面的返回值,好好看一下,相信你能看出来是怎么运行的。),然后如果该结束了,就跳出循环,我们就打印本局的结果。
🎉运行结果如下:
在这里插入图片描述

💚💚💚那么到这,就全部结束了,最上面已经展示过三个文件里的代码了,那三个是之前编译的,这次是又重新弄了一遍,所以是略有不同,不过不影响游戏的运行,那么再把这次讲解时编出的三个文件的代码图片发一下:
game.h
在这里插入图片描述
test.c
在这里插入图片描述
game.c
在这里插入图片描述
在这里插入图片描述

四、说明个别点

  • 头文件里定义的宏在三个文件都可以使用,因为剩下的那两个文件都包含了头文件。
  • 我们再梳理一下三个文件(game.c,game.h,test.c)文件之间的联系:game.h放的是其他两个.c文件(源文件)要用到的函数,算是桥梁的作用吧,game.c来具体定义再game.h里声明的函数,然后test.c再去用。
  • 三子棋里其实那些函数可以只传一个棋盘,不用穿另外两个参数,我们这里传了一下,其实是为了说明我们要灵活运用知识,这里ROW,COL和row,col都相等,我们不传也可以运用define定义的宏,但万一他们不一样呢,那么到时候我们就需要像我写的这样,多传两个参数(下此的扫雷博客就是一个很好的例子,欢迎观看)。
  • 再说一下在编译时遇到了一个问题,判断等号(==)不能连等,如果要两者以上都判定是否相等,我们要两两判定然后用&&符号连接。
  • 💚💚💚那么到这,三子棋的详细讲解就结束了,赶快动手尝试一波吧!
    🍭🍭🍭制作不易,还望给个赞鼓励一下博主继续写博客的动力!可以的话点个关注💚!!!
  • 17
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值