纯C做三子棋(超详细教程》笔记》第一期)

第一步:创建三个文件,一个主文件(就是放main函数的那个文件),名字为sanziqi.c

两个模块文件(.h.c文件),分别叫game.h,game.c,用来声明和定义

纯C做三子棋(超详细教程》笔记》第一期)_第1张图片

第二步:创建一个menu(菜单)

用来显示开始界面 纯C做三子棋(超详细教程》笔记》第一期)_第2张图片

 纯C做三子棋(超详细教程》笔记》第一期)_第3张图片

输入1就开始游戏,输入0为假就退出游戏

那么我们就创建一个test(),test()用来存放选择,test()只会被主函数main调用一次

纯C做三子棋(超详细教程》笔记》第一期)_第4张图片

如果输入1,就打印“开始游戏”,否则输入0就打印“退出游戏”,如果输入其他数就为真(非0就为真),为真就退出不了循环,就会提示你“请重新输入”,会回到循环起始位置重新输入数字,直到输入0就结束游戏,如果输入1就再开一局

把test()放main函数里进行调用,把menu()函数放test()里进行调用

纯C做三子棋(超详细教程》笔记》第一期)_第5张图片

 纯C做三子棋(超详细教程》笔记》第一期)_第6张图片

第三步:创建一个game()函数体,用来存放返回值。我们所有游戏的参数最后都放在game()里面进行封装,void类型,没有返回值,方便查找错误。

游戏参数都传给“game.c’里进行写值,最后返回game().

第一步:进行三子棋的初始化,所谓的三子棋就是一个井字:

纯C做三子棋(超详细教程》笔记》第一期)_第7张图片

 但是其实它是一个去了边界的二维表

纯C做三子棋(超详细教程》笔记》第一期)_第8张图片

 创建二维表用二维数组,我们定义一个三行三列的二维数组:board[3][3]

我们下棋的时候在表格上打印* 或者#号代表棋子,所以数组类型定义为char

为了方便后期调用,在“game.h”里面用宏定义,用ROW,COL代替二维数组的行和列,行和列的值我们赋值为3

纯C做三子棋(超详细教程》笔记》第一期)_第9张图片

 然后我们需要对这个表格进行初始化,不然我们后面下棋的时候就会发现每行每列都有数据,我们就落不了子了

inittable();//定义一个函数,初始化函数

对表格的初始化实际上就是对二维数组的初始化,所以我们需要把数组给传过去,还需要把行和列传过去发,方便计算。

inittable(board,ROW,COL);
        
 

纯C做三子棋(超详细教程》笔记》第一期)_第10张图片

提示没有标识符COL,因为我们的COL和ROW都是在"game.h"里面声明的,所以要引用一下"game.h" 

纯C做三子棋(超详细教程》笔记》第一期)_第11张图片

 把初始化函数传给"game.c",我们在game.c里面来写游戏的主体

纯C做三子棋(超详细教程》笔记》第一期)_第12张图片

接收了board和ROW,COL三个值(注:row.col小写不影响,形参名可以自己随便定) 

然后打印一个三行三列的表格

纯C做三子棋(超详细教程》笔记》第一期)_第13张图片

i

row和col其实就是我们宏定义的3

所以就是内循i<3,外循j<3

 当i循环一次,j循环3次,i循环了3次,J循环了9次,三次一行,一共三行

所以就是一个三行三列的二维数组

我们初始化把表格的三行三列全部赋一个空值

    board[i][j]=' ';

第四步:打印表格:

dayintable(board,ROW,COL);

 同样在sanziqi.c文件里的game()里面创建一个函数,然后把数组,行,列传给game.c

纯C做三子棋(超详细教程》笔记》第一期)_第14张图片

打印表格,同样打印三行三列,但是注意,我们的表格是一个#字型的

纯C做三子棋(超详细教程》笔记》第一期)_第15张图片 也就是说我们有两条线是不打印的

纯C做三子棋(超详细教程》笔记》第一期)_第16张图片先不管,先打印三行三列,同样用两个for循环

    for(int i=0;i     {
    for(int j=0;j     {

 效果图原理:用空格 | ---来打印

纯C做三子棋(超详细教程》笔记》第一期)_第17张图片

 然后呢,如果我们的i

否则当i>2的时候就不打印,这样就实现了只打印两行线的目的

纯C做三子棋(超详细教程》笔记》第一期)_第18张图片

同样的,打印两列"|"也是如此:

void dayintable(char board[ROW][COL],int row,int col)
{int j=0;int i=0;
for(i=0;i     {
    for(j=0;j     {
        if(i         {printf("---");}
    
    if(j     {printf("|");}
    }

}
}

 printf是我们stdio.h里面的函数,所以我们需要引用一下stdio.h库

 stdio.h我们声明在game.h里面,先声明再使用,这样我们的game.c就可以使用了

同样的,我们的sanziqi.c要想调用我们的初始化函数

(void inittable(char board,int row,int col))

打印函数

(void dayintable(char board,int row,int col))

也需要先声明,也声明在game.h里面

纯C做三子棋(超详细教程》笔记》第一期)_第19张图片

那么我们的sanziqi.c引用了#game.h,而game.h里面又引用了stdio.h。是不是就相当于我们的sanziqi.c引用了stdio.h,那么我们就把sanziqi.c里面的stdio.h删除就行了,只引用game.h就可以了纯C做三子棋(超详细教程》笔记》第一期)_第20张图片

 因为我们的main函数里面放的是test(),所以我们要让test()调用一下game()

纯C做三子棋(超详细教程》笔记》第一期)_第21张图片

如果输入1就调用game(),就可以初始化表格,打印棋盘,进行游戏,然后break跳出循环,不在往下走,而是进入游戏;

 需要注意,我们的test()调用game(),那么game()应该放在test()上面,否则就会提示game()未定义

纯C做三子棋(超详细教程》笔记》第一期)_第22张图片

然后我们运行一下看一下效果: 

纯C做三子棋(超详细教程》笔记》第一期)_第23张图片

没有换行,加换行符之后试试 

纯C做三子棋(超详细教程》笔记》第一期)_第24张图片

 不是我们想要的效果

事实上我们知道我们在这个二维表中存放的数据是三行三列的

纯C做三子棋(超详细教程》笔记》第一期)_第25张图片

纯C做三子棋(超详细教程》笔记》第一期)_第26张图片

只是说分隔行和分隔列只有两行而已 。

那么我们可以打印一个数据打印一个分隔列,打印一个数据打印一个分隔列,打印一个数据打印一个分隔列

即:%c|%c|%c

然后第二行呢打印分隔行 ---|---|----

那么%c|%c|%c打印三行 (即数据打印三行)   分隔行 ---|---|---只需要打印两行(即分割行打两行)

纯C做三子棋(超详细教程》笔记》第一期)_第27张图片

打印看一下:

 f3dbb31664a2499fa1b3d024e5327942.png

 这个样子是因为乱码导致的

printf("%c|%c|%c\n");%c后面需要跟数据

那我们接什么数据呢,接二维数组的数据 

当i为0时我打印第0行第0列的位置(z),第0行第1列的位置(q),第0行第2列的位置(r)

纯C做三子棋(超详细教程》笔记》第一期)_第28张图片

这样就把第一行数据给打印完了,然后i为2时,依次类推,最后就把三行三列全部数据给打印完了

纯C做三子棋(超详细教程》笔记》第一期)_第29张图片

 纯C做三子棋(超详细教程》笔记》第一期)_第30张图片

 初始化的必要性:

 如果把初始化给注释掉,然后数组那里改成符号'b';

纯C做三子棋(超详细教程》笔记》第一期)_第31张图片

那么现在打印会是什么样的呢?

纯C做三子棋(超详细教程》笔记》第一期)_第32张图片

 然后这个代码其实有上限,比如说我们要打印一个五行五列的棋盘纯C做三子棋(超详细教程》笔记》第一期)_第33张图片

 把行和列定义成5  5

纯C做三子棋(超详细教程》笔记》第一期)_第34张图片

运行之后我们发现行是5行,但列仍然是3列

 纯C做三子棋(超详细教程》笔记》第一期)_第35张图片

 我给一个优化策略,以画图的形式:纯C做三子棋(超详细教程》笔记》第一期)_第36张图片

 纯C做三子棋(超详细教程》笔记》第一期)_第37张图片

纯C做三子棋(超详细教程》笔记》第一期)_第38张图片

 优化完之后我们可以随便打印各种表盘了

    Ok,现在我们可以下棋了,首先是玩家落棋,玩家输入一个坐标,然后这个坐标如果没有被占用那么就打印一个*号,如果被占用就提示被占用了并且不会往这个坐标再输入值,
    //然后我们就把这个棋盘给打印下来,我们输入的*号就打印在这个棋盘上

创建一个玩家落子函数8a69926a0f754c98bf311ebc41f551e9.png

然后把它在game.h中声明纯C做三子棋(超详细教程》笔记》第一期)_第39张图片

这个函数在sanziqi.c中的game()中调用
 

 纯C做三子棋(超详细教程》笔记》第一期)_第40张图片

因为数组下标从0开始,所以我们在下棋输入落子坐标的时候应该从0开始输入,但是玩家不知道数组这个概念,他会从1开始输入,所以我们要考虑这种情况,把横坐标(i)和纵坐标(y)的值减1,什么意思呢

纯C做三子棋(超详细教程》笔记》第一期)_第41张图片

如图,如果我们在'z'处落子应该输入坐标(1,1),但是在玩家眼里这个坐标是(2,2),所以我们就按(2,2)输入,但是实际程序内部运行的我们让它变成(2-1,2-1)就还是(1,1)。

c48c0201a25648cc8d6f529562b25156.png

那么我们就需要敲定一个范围,我们输入的坐标范围就为:(0,0)到(3,3)之间,如果在这个范围里输入坐标,那我们就可以落子

纯C做三子棋(超详细教程》笔记》第一期)_第42张图片

然后我们需要检测我们落子的位置是不是已经有棋子了,如果有提示“这个位置已经被占用,请另选位置”,如果没有就在此处落一个棋子(玩家的棋子为*号)。

 纯C做三子棋(超详细教程》笔记》第一期)_第43张图片

纯C做三子棋(超详细教程》笔记》第一期)_第44张图片

运行纯C做三子棋(超详细教程》笔记》第一期)_第45张图片

发现有问题。坐标一直被占用。一般来说都是初始化函数出问题了,但我的二般问题,就是我的玩家落子函数里面少了一个break;纯C做三子棋(超详细教程》笔记》第一期)_第46张图片

 修正之后运行

 纯C做三子棋(超详细教程》笔记》第一期)_第47张图片

这是什么原因呢,首先,我们只输入了一次坐标,就不让接着输入了,而是让你重新选择开始游戏还是退出游戏,也就是这个游戏只能玩个开头。而我们需要不断的落子,直到游戏输赢为止。而不是落一次子就要选择重新开始还是退出

纯C做三子棋(超详细教程》笔记》第一期)_第48张图片

 修改完之后运行:

 纯C做三子棋(超详细教程》笔记》第一期)_第49张图片

 我们发现输入的值和落子的位置对不上

 纯C做三子棋(超详细教程》笔记》第一期)_第50张图片

 更改之后再运行:纯C做三子棋(超详细教程》笔记》第一期)_第51张图片

纯C做三子棋(超详细教程》笔记》第一期)_第52张图片

OK,运行成功 

接下来我们引入电脑玩家

电脑落子我们把它的x坐标,y坐标全部用随机值赋值

rand是随机值函数,范围0到RAND_MAX 

选中RAND_MAX 右键单击转到定义

纯C做三子棋(超详细教程》笔记》第一期)_第53张图片

我们发现它的值为0x7fff,转为十进制就是32767,

纯C做三子棋(超详细教程》笔记》第一期)_第54张图片

32767%10就是99,如果%10,那么就可以得到0到99之间的随机数

我们的row和col为3  3,我们%它们就可以得到0到3之间的随机值

纯C做三子棋(超详细教程》笔记》第一期)_第55张图片

而rand只能产生一个相同的随机值,就是产生了就不会发生变化了,如果让它每次都变化就需要随机种子srand

srand只能调用一次,我们把它放在我们sanziqi.c文件里的test()里面,因为test()只被调用一次。

srand需要一个指针参数 纯C做三子棋(超详细教程》笔记》第一期)_第56张图片

 我们定义一个空指针,把time强制类型转换为int类型

 然后我们需要调用一个头文件:stdlib.h

time.h

全部在game.h里面声明

纯C做三子棋(超详细教程》笔记》第一期)_第57张图片

 纯C做三子棋(超详细教程》笔记》第一期)_第58张图片

接下来就需要判断输赢了

如果三个相同的*一行或者对角线,那么玩家赢

如果三个相同的#一行或者对角线,电脑赢

如果都没赢,并且棋盘满了,那平局。

电脑和玩家每落一次棋系统都会进行判断输赢和平局,如果都没有那就继续比赛 

你可能感兴趣的:(java,开发语言)