前言
新人发文,可能有什么照顾不周的地方,请大伙多多关照!
一、三子棋是什么?
在写三子棋这个游戏之前,我们首先要知道三子棋是一个什么样的游戏。
在一定数量的格子中,画出X和O,三个字符链接到一起的时候游戏胜利
上面的图片便是三子棋的一个小长假,接下来让我们看看实现这个游戏需要什么样子的代码
二、代码的实现
1. 文件的创建
为了使检查bug更加的方便,我们这次使用三个文件来共同完成这一个小游戏,我创建的三个文件分别是
main.c
game.c
game.h
其中main.c文件中存放的是我的主函数和游戏的主要实现内容
game.h文件中存放的是我关于全局常量的定义,和一些函数的声明
而最后game.c文件中存放的是游戏函数的实现过程
2.游戏菜单的打印
首先,我们需要创建一个main函数,承担我们的接下来的代码
然后我们创建一个test函数来存放我们的主要内容(为了保持main函数的整洁)
int main()
{
test();//调用主要函数,接下来的文件会在这里完成
return 0;
}
为了玩游戏,我们首先需要打印一个可视化的游戏菜单,方便玩家对游戏进行操作。
为此,我们在test函数中调用menu函数
这一步很简单,只需要用到printf函数可以了
代码如下:
void menu()
{
//应该先打印菜单
printf("********************\n");
printf("******1. game ******\n");
printf("******0. exit*******\n");
printf("********************\n");
}
由于只承担打印的作用,所以我们将返回类型设置为void
此时的test函数
void test()
{
menu():
}
3.游戏选择部分的代码
对于这个部分,要实现一个游戏。我们此时就需要一个do…while循环,于是,再test中,我们就得到了如下代码
void test()
{
//我们此时需要一个随机数
srand((unsigned int)time(NULL));//这个再之后会讲解为什么插入的
//需要打印游戏菜单
menu();
//应该设计为循环输入
int i = 0;
do
{
printf("请选择 》");
scanf("%d", &i);
switch (i)
{
case 1:
printf("开始游戏\n");
//接下来需要让人下棋
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("请重新选择\n");
break;
}
} while (i);
}
根据menu函数来看,继续游戏是1,退出是0.正好符合了c语言的真假判断标准,所以,把i放到while循环的判断部分,很巧妙的一个方法。
4.game()函数的实现
在我们有了整个主体的操作内容之后,我们需要让游戏跑起来。所以,我们创建一个game()函数,因为我们写的游戏是一个三子棋游戏,所以我们需要一个棋盘。棋盘就需要创建一个二维数组来实现,arr[3][3]。
此时写3 3的话,虽然简单,但是实际上看,却是把代码写死了,于是,我们在game .h定义两个常量
#define HANG 3
#define LIE 3
但是在这个数组中,默认的所有数字是0,所以我们需要对其进行初始化。我这里初始化为了‘ ’。
具体代码如下:
在game.h中
//对数组进行初始化为‘ ’
void spacing(char arr[HANG][LIE], int hang, int lie);
在 game.c 中
void spacing(char arr[HANG][LIE], int hang, int lie)
{
int i = 0;
for (i = 0; i < hang; i++)
{
int j = 0;
for (j = 0; j < lie; j++)
{
arr[i][j] = ' ';
}
}
}
在对数组进行初始化完成之后,我们需要将其打印出来,所以我们创建一个打印函数。但是打印不能只打印数组,因为数组现在的内容是空格,打印出来看不到的。所以我们需要在这个附近加上分隔符
void print(char arr[HANG][LIE], int hang, int lie);
在game.c 中对应的函数为
void print(char arr[HANG][LIE], int hang, int lie)
{
//打印的棋盘是需要分割符的
int i = 0;
for (i = 0; i < hang; i++)
{
int j = 0;
for (j = 0; j < lie; j++)
{
printf(" %c ",arr[i][j]);
if (j < lie - 1)
{
printf("|");
}
}
printf("\n");
if(i < hang - 1)
{
for (j = 0; j < lie; j++)//在每个for循环中j都会重置的
{
printf("___");//打印下划线
if (j < lie - 1)
{
printf("|");//除了最后一个字符不打印 | 之外,都要打印,所以需要if来判断
}
}
}
printf("\n");
}
}
这个时候,打印出来的棋盘为
5.玩家下棋
有了棋盘之后,我们就要开始下棋了,咱们让玩家下的棋子为‘ * ’。让玩家输入坐标就好,那么,我们创建的是一个数组,获取坐标之后,首先就需要进行越界检查。由于一般的玩家是不知道数组的第一个下表是从0开始的,所以,咱们获取的坐标就一定是一个在1~hang or 1~ lie 的数字,所以在放入数组的时候需要对其坐标进行 -1.最后,我们需要检测下棋的位置是否有别的的棋子,如果有的话,就需要对其进行查重检查。
在game.h中的代码如下
//玩家走棋子
void player(char arr[HANG][LIE], int hang, int lie);
在game.c中的代码文件如下
void player(char arr[HANG][LIE], int hang, int lie)//咱们让玩家走*
{
printf("请输入坐标\n");
while (1)
{
int i, j;
scanf("%d %d", &i,&j);//这里我不小心把本应该的空格达成了,,所以导致测试老是出现错误,写代码还是需要更加的细心才行呢
//i = i - 1;
//j = j - 1;
//要做一个占位检查,还要检查数字是否合法
if (i >= 1 && i <= hang && j >= 1 && j <= lie)
{
if (arr[i -1][j - 1] != ' ')
{
printf("这个地方已经有棋子啦!重选一个吧!\n");
}
else
{
arr[i -1 ][j - 1] = '*';
break;
}
}
else
{
printf("坐标输入错误啦!重新输入一个吧\n");
}
}
}
6.电脑下棋
在玩家进行落子之后,需要电脑进行落子,由于本人的技术水平不到位,所以只能通过随机数来实现电脑落子,没法让电脑智能下棋。在之后如果有研究成果的话会发出来的。
使用随机数我们需要两个函数,一个是srand(),另一个是rand()
还需要两个头文件,由于咱们的两个.c文件中都引用了game.h,所以咱们在game.h中放入这两个头文件.
#include<stdlib.h>
#include<time.h>
然后srand函数,放到test()函数中
srand((unsigned int)time(NULL));
由于time()的返回类型为time_t,所以我们使用强制类型转换为int,然后给time一个空指针。
电脑落子的方法与玩家落子的方法大同小异,都需要进行占位检查
在game.h的代码为
void computer(char arr[HANG][LIE], int hang, int lie);
在game.c中的代码为
void computer(char arr[HANG][LIE], int hang, int lie)
{
//可以通过随机数来获得走的地方,那么就需要调用时间戳
//咱们让电脑下一个#
printf("电脑行动\n");
Sleep(1300);
while (1)
{
int i = rand() % hang;
int j = rand() % lie;
if (arr[i][j] == ' ')
{
arr[i][j] = '#';
break;
}
}
}
我这里还使用了一个sleep函数,让电脑睡一会儿,感觉更有意思(笑)
7.输赢判断
在完成了所有步骤之后,我们迎来了输赢判断的步骤
这里我有一件很可惜的事情,在之前的所有代码中,都没有写死,无论是棋盘大小和打印方法都可变,唯独在输赢判断,由于自身能力不足,所以只好写死了,我尝试的代码放在下面,待有朝一日会优化的
char arr2[HANG * LIE];//玩家数组
char arr3[HANG * LIE];//电脑数组
int n = 0;
int m = 0;
for (int i = 0; i < hang; i++)
{
int j = 0;
for (j = 0; j < lie; j++)
{
if (arr[i][j] == '*')
{
arr2[n] = i;
arr2[n + 1] = j;
n = n + 2;
}
else if (arr[i][j] == '#')
{
arr3[m] = i;
arr3[m + 1] = j;
m = m + 2;
}
}
}
int w = 0;
for (w = 0; w < hang * lie; w=w+2)
{
//人
if (arr2[w] == arr2[w + 2] == arr2[w + 4] && arr2[w] + 2 == arr2[w + 3] + 1 == arr2[w + 5])
{
return '*';
}
if (arr2[w] + 2 == arr2[w + 1] + 2 == arr2[w + 2] + 1 == arr2[w + 3] + 1 == arr2[w + 4] == arr2[w + 5])
{
return '*';
}
if (arr2[w] == arr2[w + 5] && arr2[w + 1] == arr2[w + 4] && arr2[w + 2] == arr2[w + 3] && arr2[w] != 0)
{
return '*';
}
//电脑
if (arr3[w] == arr3[w + 2] == arr3[w + 4] && arr3[w] + 2 == arr3[w + 3] + 1 == arr3[w + 5] )
{
return '#';
}
if (arr3[w] + 2 == arr3[w + 1] + 2 == arr3[w + 2] + 1 == arr3[w + 3] + 1 == arr3[w + 4] == arr3[w + 5] )
{
return '#';
}
if (arr3[w] == arr3[w + 5] && arr3[w + 1] == arr3[w + 4] && arr3[w + 2] == arr3[w + 3] && arr3[w] != 0)
{
return '#';
}
}
好,接下来我们来说这段代码的实现。
对于输赢来说,我们有四种情况:
1.玩家赢了(*)
2.电脑赢了(#)
3.平局(f)
4.继续(t)
我们要判断这四个情况,那么,我们写一个win函数,其中,我们通过棋盘是否满了来判断是否继续,所以,我们在game.c函数中嵌套一个full函数,full函数的代码如下
int full(char arr[HANG][LIE], int hang, int lie)
{
for (int i = 0; i < hang; i++)
{
int j = 0;
for (j = 0; j < lie; j++)
{
if (arr[i][j] == ' ')
{
return 1;
}
}
}
return 0;
}//判断棋盘是否放满的函数
而在win函数中对应的值为
int l = full(arr, hang, lie);
if (l == 0)//这里出现过一次错误,==千万不要写成=了
return 'f';
else
return 't';
接下来我们只需要通过穷举方法来判断胜负就好了
在game.h的代码如下
char win(char arr[HANG][LIE], int hang, int lie);
(因为我们是需要返回值的,所以类型设置为char)
在game.c的代码如下
char win(char arr[HANG][LIE], int hang, int lie)
{
//判断输赢
//检查 行
for (int i = 0; i < hang; i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
{
return arr[i][0];
}
}
//检查列
for (int i = 0; i < lie; i++)
{
if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[2][i] != ' ')
{
return arr[0][i];
}
}
//对角线
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[2][2] != ' ')
{
return arr[0][0];
}
if (arr[0][3] == arr[2][2] && arr[2][2] == arr[3][1] && arr[2][2] != ' ')
{
return arr[2][2];
}
//,判断棋盘是否摆满了
int l = full(arr, hang, lie);
if (l == 0)//这里出现过一次错误,==千万不要写成=了
return 'f';
else
return 't';
}
在main.c文件中的game()封装为
void game()
{
char ret = 0;
//目标是写一个下井字棋棋小游戏,首先需要创建一个二维数组
char arr[HANG][LIE];
//接下来需要对数组内容进行初始化
spacing(arr, HANG, LIE);
//打印棋盘,使用函数print
print(arr, HANG, LIE);
while (1)
{
//需要让玩家行走
player(arr, HANG, LIE);
print(arr, HANG, LIE);
//我们此时还需要一个函数来判断输赢 假设t为继续,#为电脑赢了,*为人赢了,f为平局
ret = win(arr,HANG,LIE);
if (ret != 't')
break;
//让电脑行走,写随机数
ret = win(arr, HANG, LIE);
if (ret != 't')
break;
computer(arr, HANG, LIE);
print(arr, HANG, LIE);
}
if (ret == '*')
printf("你赢了\n");
else if (ret == '#')
printf("你输了\n");
else if (ret == 'f')
printf("平局\n");
menu();
}
在这里我们就结束了这个游戏
希望这个文章能对你有所帮助