经验分享|Tic Tac Toe简单井字棋

前言 井字棋是我们小时候常玩的一种简单的小游戏,今天就让我们来实践一下自己做出一个井字棋。
目录
整体思路
打印菜单
初始化棋盘
打印棋盘
玩家移动
电脑移动
判断输赢
整合
项目整体

整体思路 【经验分享|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"); } }

打印效果如图(棋盘为空的情况下):
经验分享|Tic Tac Toe简单井字棋
文章图片

玩家移动 当玩家开始下棋的时候我们利用 ” * “ 来代表一个棋子,但是众所周知,井字棋不一定每次都可以分出胜负,也就是说,我们还需要考虑到期盼已经被下满的情况,因此玩家下棋的时候我们总共要考虑到一下几点:
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)

    推荐阅读