目录

一.前期准备

二.游戏逻辑结构

三.游戏主体框架

四.游戏主体实现

1.制作棋盘

2.玩家下棋

3.电脑下棋

4.判断胜负关系

五.游戏后期框架


fdgdgdfgd

一.前期准备

在我写这个游戏时,我发现后期会有很多函数要存储,还要经常传递棋盘的行和列,调用函数库,所以我强烈建议写一个头文件去存储行列信息,包含函数库,对函数进行声明等操作,既能方便书写,还能让代码更有流程和条理性。

建立一个game.h头文件:存储行列信息,包含函数库,对函数进行声明

建立一个game.c文件:实现游戏中的函数

建立一个test.c文件:实现函数主体逻辑,在书写时可用此函数进行测试

将game.c和test.c文件中包含#include“game.h”

二.游戏逻辑结构

写这个“三子棋”游戏前我们回想一下这个游戏个规则:

两个玩家,分别用不同花色的棋子,轮流在3乘3的棋盘上下棋,最先三子连线的玩家胜利。如果棋盘下满并且双方都下得正确无误,将平局。

因为要在程序中玩游戏,我们只写玩家操作界面的话,只能自己和自己下棋,这样好傻,要不就是让另一个玩家与你下棋,但我更希望搞一个代替玩家的电脑来和你下棋,所以我们把其中一个玩家替换成电脑。

游戏主要逻辑结构变更为:

玩家和电脑轮流下棋,当棋盘上有三个相同花色的棋子相连时,则决出获胜方

当棋子占满棋盘并且没有获胜方,则双方平局

我们可以拆分一下主要逻辑

1.电脑和玩家轮流下棋

2.三个相同花色的棋子相连,游戏结束,判断出获胜方

3.棋子占满棋盘,游戏结束,双方平局

想要在代码中实现上面的逻辑我们需要先创建一下游戏的大体框架

三.游戏主体框架

我们设想一下游戏一进去一般都会显示什么

大部门游戏进去都会显示“开始游戏”“设置”“退出游戏”等选项

这里我们设计一下当三子棋游戏程序打开后,给出玩家两个选项,“开始游戏”还是“退出游戏”,方便游戏整体的进行和退出。

我们引入“input”来控制游戏的进行和退出

当输入1-进行游戏 0-退出游戏

在这里利用do while循环有两个好处:1.一打开游戏可以先打印游戏菜单去询问玩家进行的操作再去做出判断2.while(input)当input为0时刚好跳出while循环结束游戏

——test.c

int main()
{int input = 0;do{menu();     //打印游戏菜单printf("请输入:>");scanf("%d", &input);switch (input){case 1:game();     //进行游戏break;case 0:break;default:printf("输入错误
");      //当输入不是1或0时提醒输入错误break;}} while (input);                    return 0;
}

你会发现我在里面设计了一个“menu”函数和“game”函数

“menu”函数功能:打印游戏菜单

这里我们设计一个简单的游戏菜单

——game.c

void menu()
{printf("**********************
");printf("********1.PLAY********
");printf("********0.EXIT********
");printf("**********************
");
}

并且在

——game.h声明函数

void meun();

经过上放主函数中的while循环就可以多次调用“menu”函数,在必要时刻提醒玩家应该输入什么进行游戏,这样逻辑结构就进一步改变

下面我们就去实现“game”函数一步步将游戏的功能和细节补充到位

四.游戏主体实现

1.制作棋盘

当进入游戏后,我们要呈现一个可视化的棋盘,去给玩家操作

左边是我们日常玩的三子棋棋盘样式,右边是我在C语言中用字符组成的三子棋棋盘,我感觉很相似了哈哈

然后我们在棋盘表上行号和列号,有没有发现标上后非常像二维数组

所以顺藤摸瓜,这里我们用二维数组来存储棋盘的数据

因为要经常用到棋盘的行与列且行与列不会轻易变动所以我们在“head.c”文件中宏定义两个量ROW和COL,这样后期用起来十分的方便

——game.h

#define ROW 3
#define COL 3

到后面你会逐渐发现这样写的好处,假如你想改成四子棋或者五子棋等等,你只要在定义行和列的代码段中修改行和列的数字大小就可以实现

现在我们仔细窥探这个棋盘,我们仅需在红框中下入棋子即可,其他的字符只是用来组成棋盘的,中间最重要的“变量”还是方框中要存储的是“字符”,所以这里我们利用好我们的二维数组的知识,创建一个数组arr[ROW][COL],并将其创建在“game.c”下的“game”函数中

——test.c

void game()
{char arr[ROW][COL];       //存储棋盘数据
}

因为在棋盘中没有下棋时,也要在数组中存储信息,打印出来的红框部分默认是字符“空格”,这里我们在“game.c”’中写一个初始化函数“InitBorad”将“空格”字符赋值给board数组中

——game.c

void InitBoard(char arr[ROW][COL],int row,int col)
{//遍历赋值int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){arr[i][j]=' ';}}
}

不要忘了在“game.h”中声明该函数!!!

下面我们就要尝试打印棋盘了

我们继续窥探这个棋盘

会发现这个棋盘是由5行字符组成的

其实我们只需要传参“arr[ROW][COL]”数组“ROW”和“COL”后经过组合就可以拼出这个棋盘的图形

方法:我们把相似的行看成一组1,3,5为一组2,4为一组这样每组一个for循环,假如换行符,加上限制条件,就可以轻易的写出一个新的打印函数“Printboard”

——game.c

void PrintBoard(char arr[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){//输出棋格,每输出一格就输出一个'|'字符来分隔开for (j = 0; j < col; j++){printf(" %c ", arr[i][j]);   //当到输出最后一格棋格后,不再输出'|'字符if (j != col - 1){printf("|");}}//输出完一行记得换行printf("
");//输出完棋格,记得输出棋盘中的2,4行作为棋盘分界线if (i != row - 1){for (j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}printf("
");}}
}

不要忘了在“game.h”中声明该函数!!!

这种写法有一个好处那就是当你在修改“game.h”中的ROW和COL后,可以打印出对应的棋盘,操作简单不需要再去修改“PrintBoard”函数,并且这种写法修改数组元素后再打印,棋子可以直接显示在棋盘上,十分方便

2.玩家下棋

因为双方都要在这个棋盘上下棋,所以我们拟定一下玩家的棋子的花色

玩家:*

“PrintBoard”函数写好后,我们只要改数组元素就可以进行下棋操作这里我们一个函数

“PlayerMove”:玩家下棋

大体思路就是输入坐标修改数组元素,先判断坐标合法性,再判断输入的坐标是否有棋子了,最后把数组元素赋值玩家和电脑所对于的字符

这里要注意,当输入1 1坐标时其实是给arr[0][0]进行修改,玩家并不知道数组的元素是从0开始的,所以我们记得将输入行和列的坐标-1后再修改数组对应元素

void PlayerMove(char arr[ROW][COL],int row,int col)
{int x = 0;int y = 0;//提示玩家下棋printf("玩家走:>
");//while循环作用:当玩家输入以有棋子的坐标或坐标输入错误时可以重新输入再次下棋while (1) {//规定好输入坐标的格式printf("请玩家输入棋子坐标(行数空格列数):");scanf("%d%d", &x, &y);//先判断坐标是否非法if (x > 0 && x <= row && y > 0 && y <= col){//判断该坐标是否有棋子,玩家输入的坐标反应到数组中时要-1if (arr[x - 1][y - 1] == ' '){arr[x - 1][y - 1] = '*';break;}else{//有棋子在此坐标时会提示printf("坐标被占用请重新输入请玩家输入棋子坐标(行数空格列数):
");}}else{//坐标输入错误时提示printf("坐标非法,请重新输入:
");}}
}

不要忘了在“game.h”中声明该函数!!!

配合“PrintBoard”函数,就可以以可视化的效果继续游戏

3.电脑下棋

拟定电脑棋子花色

电脑:#

电脑下棋需要电脑去判断,这里我用的是生成伪随机数作为电脑的下入棋子的坐标,我们创建一个函数

“ComputerMove”函数

伪随机数的生成我用的是“rand”函数和时间戳“time”函数的配合

——head.h

#include<time.h>

——test.c     在input后添加一个srand函数,作为初始化随机数的发生器并接收时间戳的值,就可以使用“rand”函数了

int main()
{int input = 0;srand((unsigned int)time(NULL));
}

——game.c

//电脑下棋
void ComputerMove(char arr[ROW][COL], int row, int col)
{printf("电脑走:>
");int x = 0;int y = 0;while (1){//生成随机坐标,模除是为了把坐标控制在0-2x = rand() % row;y = rand() % col;//如果输入的坐标被占用我们就利用while循环再次生成随机数直到找到一个空坐标if (arr[x][y] == ' '){arr[x][y] = '#';break;}}
}

不要忘了在“game.h”中声明该函数!!!

配合“PrintBoard”函数,就可以以可视化的效果继续游戏

4.判断胜负关系

玩家和电脑的操作我们都写完了,下面就该判断胜负关系了

创建一个“Is_Win”函数去判断谁胜利了,函数在每次玩家或者电脑下棋后就进行调用进行判断

判断有四种可能性,我们用返回值来区别可能性

1.玩家胜利:返回字符'*'

2.电脑胜利:返回字符'#'

3.平局:返回字符'Q'

4.继续游戏'C'

先判断是否有胜利,再去判断谁胜利。

游戏胜利的三种可能性和:

1.单行所有字符相同并且不是字符' '

2.单列所有字符相同并且不是字符' '

3.对角线所有字符相同并且不是字符' '

平局:

只要我们的棋子数量等于行*列,并且没有获胜者,就可以判断平局

继续游戏

只要arr数组中还有元素为字符' '就可以继续游戏

1.实现行判断就要for循环中循环行,对每一行都进行判断,再在其中嵌套for循环循环列,然后判断

2.实现行判断就要for循环中循环列,对每一列都进行判断,再在其中嵌套for循环循环行,然后判断

3.判断对角线相同只要把arr[0][0],arr[1][1],arr[0][2]坐标和另一条对角线arr[0][2],arr[1][1],arr[2][0]判断即可

注意我们判断是否胜利的代码方式有很多种,介绍下面的一种是因为:建立了一个count来记录相同的字符有几个,每当count==ROW时就可以跳出,并且当我们在“game.c”中修改“ROW”和‘“COL”时不用再次修改“Is_Win”函数,这种写法不用再次修改十分方便,

return返回时直接返回元素坐标可以直接打到上面我们设计的返回内容

//用char返回值,可以在后面搭建game函数时快速判断
char Is_Win(char arr[ROW][COL], int row, int col)
{char ret = 0;int count = 0;int x = 0;int y = 0;int i = 0;//判断行是否成立for (x = 0; x < row; x++){count = 0;ret = arr[x][0];for (y = 0; y < col; y++){if (arr[x][y] == ret&&arr[x][y]!=' '){count++;}}if (count == col){return arr[x][0];}}//判断列是否成立for (y = 0; y < col; y++){count = 0;ret = arr[0][y];for (x = 0; x < row; x++){if (arr[x][y] == ret && arr[x][y] != ' '){count++;}}if (count == col){return arr[0][y];}}//判断两条对角线count = 0;ret = arr[0][0];for (i = 0; i < row; i++){  if (arr[i][i] == ret && arr[i][i] != ' '){count++;}if (count == col){return arr[0][0];}}count = 0;ret = arr[0][col];for (i = 0; i < row; i++){if (arr[i][col - i] == ret && arr[i][col-i] != ' '){count++;}if (count == row){return arr[0][col];}}count = 0;for (x = 0; x < row; x++){for (y = 0; y < col; y++){if (arr[x][y] == ' '){return 'C';}else{count++;}}}if (count == row * col){return 'Q';//平局}
}

不要忘了在“game.h”中声明该函数!!!

五.游戏后期框架

下面只要我们把其他框架在“test.c”的“game”函数中搭建就可以完成整个游戏程序

其中最重要的是while循环的搭建,我们只要合理的利用“Is_Win”函数的返回值,判断情况,最后输出结果就可以完成此程序

——test.c

void game()
{char arr[ROW][COL] = { 0 };InitBoard(arr,ROW,COL);PrintBoard(arr, ROW, COL);char ret = 0;while (1){PlayerMove(arr, ROW, COL);PrintBoard(arr, ROW, COL);ret = Is_Win(arr, ROW, COL);if (ret != 'C'){break;}ComputerMove(arr, ROW, COL);PrintBoard(arr, ROW, COL);if (ret != 'C'){break;}}if (ret == '*'){printf("玩家胜利
");}if (ret == '#'){printf("电脑胜利
");}if (ret == 'Q'){printf("平局
");}}

看到这里恭喜你整个程序的学习已经完成!!!

写完后赶快玩一把吧!

洋洋洒洒几千字的编写不容易,gif动图做起来也很麻烦,求求给个赞吧!!!

C语言自制小游戏:三子棋(井字棋)游戏(超详细)相关推荐

  1. C语言第十课:编写井字棋游戏(综合练习1)

    目录 前言: 一.文件建立: 1.头文件game.h: 2.函数定义文件game.c: 3.工程测试文件test.c: 二.编写井字棋游戏: 1.程序整体执行思路: 2.menu菜单函数实现: 3.g ...

  2. 【C语言从入门到入土】——“井字棋”

    目录 1.游戏规则 2.设计思路 1.棋盘的初始化 2.打印棋盘 3.玩家操作 4.电脑下棋 6.输赢判断 7.完整代码展示 1.游戏规则 井字棋又叫三子棋,作为童年经典小游戏,相信各位无论是在上课摸 ...

  3. 组合游戏系列5: 井字棋、五子棋AlphaGo Zero 算法实战

    来源 | MyEncyclopedia 上一篇我们从原理层面解析了AlphaGo Zero如何改进MCTS算法,通过不断自我对弈,最终实现从零棋力开始训练直至能够打败任何高手.在本篇中,我们在已有的N ...

  4. 【c语言五子棋】自定义类型五子棋/井字棋:胜负判断

    一.算法思路 由于五子棋规则比较简单,我们可以胜负判断分为以下几个方面分别判断: 1:横向判断 2,竖向判断 3.斜向判断(从左下到右上) 4.斜向判断(从左上到右下) 二.算法原理(算法来源) 参考 ...

  5. qt制作棋牌游戏之XO棋(井字棋)

    原理很简单,就是点击鼠标进行下子,电脑与你进行博弈 没事做做还是挺有意思的. 源码在下面: mylabel.h #ifndef MYLABEL_H #define MYLABEL_H#include ...

  6. 用Unity3D实现简单的井字棋小游戏

    用Unity3D实现简单的井字棋小游戏 项目地址 井字棋小游戏 完成效果图 实现思路 首先定义游戏的数据部分: /* 井字棋中每一个棋格中的逻辑控制常量,代表这个棋格的状态 */ private co ...

  7. 基于Unity设计的井字棋小游戏

    资源下载地址:https://download.csdn.net/download/sheziqiong/86871335 资源下载地址:https://download.csdn.net/downl ...

  8. java——博弈算法实现井字棋游戏

    通过java语言开发了一个简单的井字棋游戏.主要有6个类,其中有一个是主类(Main.java),一个是抽象类(PiecesMove.java)组成. 下面对各个类简单介绍一下: TicTicToe. ...

  9. 用IE网页学游戏-井字棋

    IE网页学游戏-井字棋 井字棋实现交互的简单小游戏,学习使用表格,理解javascript函数. 1.构造棋盘 用table元素的行列构造三行三列的表格.设置好120像素的井字棋背景,三个小图表示方格 ...

  10. 3D游戏编程与设计-井字棋

    3D游戏编程与设计-井字棋 目录 3D游戏编程与设计-井字棋 A. 简答题 1. 解释游戏对象(GameObjects)和资源(Assets)的区别与联系 ① 游戏对象 ② 资源 2. 下载几个游戏案 ...

最新文章

  1. 控件包含代码块,因此无法修改控件集合
  2. Linux下逻辑地址-线性地址-物理地址图解
  3. 7-5 流水作业调度 (10 分)(思路+详解+johnson解析)Come Baby!!!!!!!!!!
  4. 车牌识别EasyPR(5)——文字定位
  5. python打印字符串全排列_【算法15】字符串的全排列
  6. java xml 解析 列表_用Java解析高级XML
  7. 【POJ2887】Big String(块状链表,模板)
  8. 距离矢量路由算法_计算机网络自学笔记:选路算法
  9. 学python前端需要哪些基础知识_前端基础知识整理回顾~~
  10. 生活与工作原则-Ray Dalio
  11. 最值得收藏的 数值分析 全部知识点思维导图整理(东北大学慕课课程)(持续更新中)
  12. Ubuntu双系统、ROS、软件安装教程
  13. 筛选过的 Code rule
  14. 计算机无法识别新u盘,电脑新装win7系统就无法识别u盘怎么办
  15. php strpos注意问题坑,关于PHP中的strpos的问题
  16. 服务器端获取签名直传OOS
  17. 头戴式耳机跑步方便吗、公认最好的跑步耳机排行榜
  18. C/C++:实现精灵游戏
  19. Ruby 安装 - Windows
  20. ecm titanium_如何使用Titanium Backup备份和还原Android手机

热门文章

  1. unity3D学习笔记2
  2. couchbase java view_基于Java的Couchbase使用入门
  3. 从DOS中装操作系统时要加载smartdrv命令
  4. 计算机软硬件配置在哪里查,如何查看电脑硬件配置信息?
  5. 1Checker(易改英文校对软件)官方中文版V2.0.1.5 | 易改英语单词检查软件下载
  6. html数值计算计算
  7. Ubuntu18.04安装mysql8.0.XX
  8. 电脑cpu测试软件 95,Prime95(CPU稳定性测试)
  9. 国产手持式频谱分析仪中性价比最高
  10. Android混淆文件配置