前言 井字棋是我们小时候常玩的一种简单的小游戏,今天就让我们来实践一下自己做出一个井字棋。
目录
整体思路
打印菜单
初始化棋盘
打印棋盘
玩家移动
电脑移动
判断输赢
整合
项目整体
整体思路 【经验分享|Tic Tac Toe简单井字棋】有一句话小黄非常赞同,”敲代码是一个项目中最简单的步骤,单纯的敲代码就和放积木一样没意思,只有决定如何去拼这个积木的时候才是最有挑战性的“。所以在完成类似的项目前,我们首先要制定一个整体的思路,然后按照框架一步步实现我们所需要的功能,才能做到快速高效的完成代码。
打印菜单 首先为了增加项目的可读性,我们可以简单加一个菜单,让玩家决定是否开始游戏,代码如下:
void meun()
{
printf("------------------------------\n");
printf("----------1.游戏开始----------\n");
printf("----------0.游戏结束----------\n");
printf("------------------------------\n");
printf("请选择->");
}
初始化棋盘 井字棋是一个 3* 3 的棋盘,那么为了去表达棋子有哪些,我们采用一个字符类型的二维数组来记录当前其棋盘内的棋子。而为了可以重复开始游戏,我们每次进行完一句游戏也需要将棋盘清空,所以设置一个可以清空棋盘的函数,而之后需要打印棋盘,故初始化为空格字符,具体如下:
void IntBoard(char arr[lie][hang], int Lie, int Hang)
{
int m, n;
for (m = 0;
m < Lie;
m++)
{
for (n = 0;
n < Hang;
n++)
{
arr[m][n] = ' ';
}
}
}
打印棋盘 为了增加可玩性,我们肯定不希望每一次下棋都需要我们自己去记住位置,因此需要设置一个可以打印当前棋盘的函数,在每次下棋之后都打印一次棋盘,具体代码如下:
void DisplayBoard(char arr[lie][hang], int Lie, int Hang)
{
intm, n;
for (m = 0;
m < Lie;
m++)
{
for (n = 0;
n < Hang;
n++)
{
printf(" %c ", arr[m][n]);
if (n < Hang - 1)
printf("|");
}
printf("\n");
if (m < Lie - 1)
printf("---|---|--- \n");
}
}
打印效果如图(棋盘为空的情况下):
文章图片
玩家移动 当玩家开始下棋的时候我们利用 ” * “ 来代表一个棋子,但是众所周知,井字棋不一定每次都可以分出胜负,也就是说,我们还需要考虑到期盼已经被下满的情况,因此玩家下棋的时候我们总共要考虑到一下几点:
1/ 下子的地方是否有效?即是否超出界外或者已经有棋子存在。
2/ 棋盘上是否还能落子?即棋盘上的棋子数量少于等于九个。
具体代码实现如下:
void playermove(char arr[lie][hang],int *n) // n利用传址调用,实现对整个棋子数量的改变
{
printf("轮到您下子了->");
int x, y;
while (1)
{
scanf("%d%d", &x, &y);
if (arr[x - 1][y - 1] == ' ')
{
arr[x - 1][y - 1] = '*';
++(*n);
break;
}
else
printf("你妈的看不到那里不能走吗?\n");
}
}
电脑移动 我们在此采用利用生成随机数的方式来模拟电脑下棋,当然这种方式下的电脑会显得特别的”蠢“。但是无妨,在此我们主要展示如何解决井字棋这样一个项目,至于如何提升电脑获胜概率可以自己思考一下。随机数我们采用srand函数来设置种子。
在此值得注意的是,种子的设置需要放在函数之外,即游戏开始之前,这样可以避免重复设置种子导致电脑下棋时间很长,因为我们随机数也是需要判断是否可以落子的,因此随机数有可能需要多次生成,若每次生成都设置一次种子,将造成很多时间浪费,具体代码实现如下:
void computermove(char arr[lie][hang],int *a)
{
int m, n;
printf("轮到电脑下子了->\n");
Sleep(2000);
while (1)
{
m = rand() % 3;
n = rand() % 3;
if (arr[m - 1][n - 1] == ' ')
{
arr[m - 1][n - 1] = '#';
++(*a);
break;
}
}
}
判断输赢 判断输赢的方式还是很简单的,判断每一行每一列以及两个斜向是否是同一种棋子即可,当我们发现是同一种棋子的时候,用一个char类型的变量记录下这个棋子,然后对其进行判断即可,同时判断是否平局也要在这一步进行,当棋子数量达到9且没有满足前面的输赢的条件时,我们就选择输出平局,并结束此局游戏,具体代码实现如下:
void iswin(char arr[lie][hang], int *n)
{
int i;
char k = ' ';
for (i = 0;
i < lie;
i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
{
k = arr[i][0];
break;
}
else if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[0][i] != ' ')
{
k = arr[0][i];
break;
}
else if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[1][1] != ' ')
{
k = arr[1][1];
break;
}
else if (arr[2][0] == arr[1][1] && arr[1][1] == arr[0][2] && arr[1][1] != ' ')
{
k = arr[1][1];
break;
}
}
if (k == '*')
{
printf(" You Win! \n");
*n = 10;
}
else if (k == '#')
{
printf(" Compuer Win! \n");
*n = 10;
}
else if (k == ' ' && *n == 9)
{
printf(" 平局 \n");
*n = 10;
}
}
整合 至此,整个游戏所需要的基本的函数我们已经全部完成,接下来,我们利用一个game函数来表示开始进行的游戏,并且把这些函数整合起来 ,同时进行一些简单的小调整,列如先前判断输赢是以函数实现的,不能直接退出game这个函数,因此单独在每次判断输赢之后加一个判断棋子数量是否未10,而棋子数量为10只有判断输赢条件成立之后对其赋值才可以实现。具体代码实现如下:
void game()
{
char Board[lie][hang];
intn = 0;
char m = 0;
IntBoard(Board, lie, hang);
DisplayBoard(Board, lie, hang);
while (1)
{
playermove(Board, &n);
DisplayBoard(Board, lie, hang);
iswin(Board, &n);
if (n == 10)
break;
computermove(Board, &n);
DisplayBoard(Board, lie, hang);
iswin(Board, &n);
if (n == 10)
break;
}
}
项目整体 小黄在这里采用了函数分开的写法,即多文件的写法,因此将其上传到了码云,可自取,地址如下:Tic Tac Toe · 濡白/Some topics - 码云 - 开源中国 (gitee.com)
推荐阅读
- 个人的小白成长经历|【濡白的C语言】初学者-从零开始-5(模块化设计——函数,传值和传址)
- 算法技巧|python算法技巧——贪心算法练习及掌握
- c语言|C语言指针进阶详解
- c语言指针进阶版
- C语言|C语言指针进阶(更加深入地了解指针)
- Leapmotion|LeapMotion项目实践(一)-- 手势识别_猜拳+数字(经验满满+各种BUG经验总结+有运行动图)
- c语言学习记录|C语言指针进阶学习
- 面试题|【Java实习生面试题系列】-- 多线程篇四
- 自学教程|<数据结构>链式二叉树的基本操作