敢于我的电脑较量五子棋么?
文章目录
- 一、三子棋游戏简介
- 二、游戏实现流程
- 1.前期准备
- 2.游戏实现的大体思路
- 1.游戏大体框架
- 2.game函数的粗略分析
- 3.game嵌套函数的实现
- 1.初始化函数 InitBoard 的实现
- 2.棋盘展示函数 DisplayBoard 的实现
- 3.实现玩家落子 PlayerMove 的实现
- 4.实现电脑落子 ComputerMove 的实现
- 5. 游戏状态的判断 以及函数的实现
- 4.game函数的完整实现
- 三、源码下载及效果显示:
- 四、后记
一、三子棋游戏简介
我想大家应该都玩过五子棋,三子棋的玩法和五子棋是一样的,五子棋是不论横竖还是对角先连成一条线就算赢了,而你的对手要想尽办法阻止你,同时也要让自己的五颗棋子连成一条线,而三子棋和五子棋的原理是一样的,只不过从五子变成了三子。
二、游戏实现流程
1.前期准备
要想实现三子棋游戏首先要创建一个名叫三子棋的工程,要创建一个game.c 源文件用来实现三子棋程序中的函数,还要创建一个test.c的源文件来实现三子棋游戏的大体框架,并进行实现游戏逻辑的测试等,以及实现电脑智能化下棋的文件实现电脑智能化.c ,还有要创建一个头文件game.h来实现三子棋函数的声明以及定义一些具有常属性的变量,和声明一些在game.h和test.c中要使用的头文件。
- game.h
- game.c
- tese.c
- 实现电脑智能化.c
2.游戏实现的大体思路
1.游戏大体框架
首先我们要实现一个菜单,每当程序运行时会出现一个菜单,显示给我们可以选择的选项
其次我们要先搭建好程序的大体结构,这个程序我们的设定是可以无限次进行游戏,直至玩家退出游戏,所以我们可以知道这个游戏应该具有一个主循环,而且这个循环最少要执行一次,所以采用do- while的循环。
当我们进入循环后,首先我们要调用菜单,然后提示我们输入选项,当我们输入后,我们可以执行相应的函数,这里涉及一个分支选择的问题,所以我们要使用switch-case来实现,在菜单中我们设置1为play开始游戏,0为exit退出游戏,所以case 1:中应该具有一个函数来实现游戏的具体功能,而case 2:里应该实现游戏的退出,并且还要有一个default来实现错误的判断,如果选择错误提示用户重新输入,最后while的判断条件应该是你输入的选项值,以此来控制游戏主循环的运行。
#include "game.h" #include<stdlib.h>void menu() {printf("********************\n");printf("******* 1.play *****\n");printf("******* 0.exit *****\n");printf("********************\n"); }void game() {//储存数据-二维数组char board[ROW][COL];//初始化棋盘 - 初始化空格InitBoard(board, ROW, COL);//打印一下棋盘 - 本质是打印数组内容DisplayBoard(board, ROW, COL);char tmp = 0;while (1){//玩家走PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断玩家是否赢得游戏tmp = IsWin(board, ROW, COL, '*');if (tmp != 'C'){break;}//电脑走ComputerMove(board, ROW, COL, '#');DisplayBoard(board, ROW, COL);//判断电脑是否赢得游戏tmp = IsWin(board, ROW, COL, '#');if (tmp != 'C'){break;}}if (tmp == '*'){printf("玩家获胜\n");}else if (tmp == '#'){printf("电脑获胜\n");}else{printf("平局\n");}DisplayBoard(board, ROW, COL); }int main() {int input = 0;do{menu();printf("请选择: >");scanf("%d", &input);switch (input){case 1:printf("三子棋游戏\n");game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0; }
2.game函数的粗略分析
游戏的大体框架已经实现,我们要来实现一下game函数具体是怎么运行的,我们将game函数放在test.c中
game函数应包含的功能:
1.首先我们要创建一个二维数组来储存玩家和电脑下棋的棋子;
2.其次game函数应该可以初始化棋盘,当玩家和电脑都未落子时棋盘应为空,需要创建一个可以初始化的函数;
3.game函数应该可以打印棋盘,需要创建一个可以打印棋盘的函数;
4.game函数应该可以实现玩家和电脑分别落子,并在落子后打印棋盘,需要创建玩家落子和电脑落子的函数;
5.game函数应该具有判断谁获胜的能力,并在有人获胜后停止继续下棋,并输出谁获胜,并打印棋盘,需要创建判断获胜条件的函数;
3.game嵌套函数的实现
1.初始化函数 InitBoard 的实现
在每一次开始游戏之前要求保证棋盘为空,故每次开始游戏之前要对棋盘进行初始化,初始化代码如下。
void InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){board[i][j] = ' ';}}
}
2.棋盘展示函数 DisplayBoard 的实现
初始化棋盘后我们要打印棋盘来观察一下,每次玩家和电脑下完棋后我们也要看棋盘,以为每次下棋我们保存在二维数组里,我们要打印棋盘,不光要输出二维数组还要输出棋盘的形状,我们这里对棋盘的形状不做过多要求,如下图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UAQfrXUT-1621075382416)(E:\图片\Cache_4ec102abfdb94e52…jpg)]
对于这个棋盘的实现,我们可以看到,在行上每当我们输出一个棋子时会输出一个数杠,但输出最后一个数时没有竖杠输出,同理列也是如此, 以上想法转换为代码为如下所示。
void DisplayBoard(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);//输出棋盘上的每棋子if (j < col - 1)//最后一列不设竖杠{printf("|");}}printf("\n");if (i < row - 1){int j = 0;for (j = 0; j < col; j++){printf("---");//最后一行不设横杠if (j < col - 1){printf("|");}}printf("\n");}}
}
3.实现玩家落子 PlayerMove 的实现
首先要知道玩家落子并不是一次就会成功,有可能或出现落子到棋盘外或者想要落子的位子已经被占用的情况,这个时候就要重新落子,知道落子成功,所以我们应该可以理解为这是一个循环的过程,直达成功落子,否则无限循环,其次我们要明白,我们是将棋子落到二维数组中,二维数组的下标与我们实际输入的落子位置是不一样的,比如我们想将棋子落到棋盘上第一行第一列的位置,实际上数组的下标应该为 0 0, 所以我们可知我们要落子的位置比我们实际数组中储存的位置大1, 其次我们要设置条件防止,落子的位置越界和重复,以上就是实现 PlayerMove需要注意的一些问题。下面我们来看代码。
void PlayerMove(char board[ROW][COL], int row, int col)
{int x = 0; int y = 0;printf("玩家走: >\n");while (1){printf("请输入下棋的坐标: >");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){//下棋//判断坐标是否被占用if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;} else{printf("坐标被占用,请重新输入。\n");}}else{printf("坐标非法,请重新输入。\n");}}
}
4.实现电脑落子 ComputerMove 的实现
在实现电脑落子时我们赋予电脑智能的落子,也就是说我们为电脑编写好了如何应对玩家落子的方法,让电脑在阻止玩家获得胜利的同时也有可能获得胜利,实际上,让电脑智能化的主要思想是,通过计算棋盘上的每一个落子点的分值来判断电脑下在哪一个位置是最合适的,遍历棋盘上的每一个位置,判断前位置是否为空,以及当前位置的四周是否为空,如果不为空判断有几颗相连的棋子,考虑1,2,3,4颗棋子相连的情况,并判断相连棋子是否为相同棋子,如是相同的棋子,接下来判断是否为我方棋子(站在电脑的角度考虑)如果是我方棋子则加十分,如果为对方棋子,则加二十分,实际上电脑拦截对手获胜的优先级大于自己获胜的优先集 ,所以我们在考虑分值是要注意这个问题, 在本代码里还考虑了,有三颗棋子相连一边没有棋子的分值,以及有四颗棋子一边没有棋子的情况,以及在中间没棋子两边有棋子的情况,最后通过比较得到最大的值,并在最大的值对应的下标处落子。
具体代码放在GitHub 和gitee中
github源码链接
gitee源码链接
5. 游戏状态的判断 以及函数的实现
当每一次玩家和电脑都落子后需要判断游戏的状态,以确定游戏的进程,游戏的状态分为四种:
- 玩家胜利 - *
- 电脑胜利 - #
- 平局 - 棋盘已满代表平局 Q
- 未分出胜负继续下棋 C
在这部分我们需要两个函数,一个 IsWin 函数判断输赢,一个IsFull函数来判断棋盘是否已满,在IsWIn函数中我们通过比较每一行每一列,以及对角线上的5个棋子是否连成一条线来判断输赢,如果直到棋盘满了都未曾分出胜负,则视为平局,如果即为分出胜负,也不是平局则继续游戏。
IsWin函数和IsFull函数的实现如下所示:
char IsWin(char board[ROW][COL], int row, int col, char ret)
{int i = 0;int j = 0;int num = 0;//判断五行for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == board[i][j+1] && board[i][j] == ret){num++;if (num == 4)//五颗棋子需要进行四次比较{return ret;}}else{num = 0;//必须是五颗棋子连在一起否者重新计数}}}//判断五列for (j = 0; j < col; j++){for (i = 0; i < row; i++){if (board[i][j] == board[i+1][j] && board[i][j] == ret){num++;if (num == 4){return ret;}}else{num = 0;}}}
//判断对角线for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == board[i+1][j+1] && board[i][j]== board[i + 2][j + 2] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4] && board[i][j] == ret){return ret;}}}for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == board[i + 1][j - 1] && board[i][j] == board[i + 2][j - 2] && board[i][j] == board[i + 3][j - 3] && board[i][j] == board[i + 4][j - 4] && board[i][j] == ret) {return ret;} }}//判断平局//如果棋盘满了返回1,不满返回0;int ful = IsFull(board, row, col);if(ful == 1){return 'Q';//平局}//继续游戏return 'C';
}
4.game函数的完整实现
在game函数嵌套函数的实现完成后用一些语句来将其来连接得到完整的game函数,其中需要注意的是,下棋的过程本就是循环的过程,但是始终要有跳出循环的过程,我们设置一个点来跳出循环,并且我们不再循环内部判断输赢,而是跳出之后在判断输赢,这样不仅使IsWin函数更加简洁,并且提高了函数的独立性,在这里我们设置的跳出循环的点是IsWin函数的返回值ret, 如果函数返回值不为C则跳出循环,否则继续循环直到棋盘下满返回Q,跳出循环后,判断函数返回值是还是#,如果是号则玩家获胜,如果实#号电脑获胜,否则为平局,代码如下。
void game()
{//储存数据-二维数组char board[ROW][COL];//初始化棋盘 - 初始化空格InitBoard(board, ROW, COL);//打印一下棋盘 - 本质是打印数组内容DisplayBoard(board, ROW, COL);char tmp = 0;while (1){//玩家走PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断玩家是否赢得游戏tmp = IsWin(board, ROW, COL, '*');if (tmp != 'C'){break;}//电脑走ComputerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断电脑是否赢得游戏tmp = IsWin(board, ROW, COL, '#');if (tmp != 'C'){break;}}if (tmp == '*'){printf("玩家获胜\n");}else if (tmp == '#'){printf("电脑获胜\n");}else{printf("平局\n");}DisplayBoard(board, ROW, COL);
}
三、源码下载及效果显示:
三子棋游戏github源码链接
三子棋游戏gitee源码链接
效果展示:
四、后记
本次代码实现了电脑的智能下棋,但是仍然存在很多不足的地方,比如初衷是要实现三子棋,但是最后却做成了三子棋,没有实现代码的灵活性,其最终最优版本应该是,能够实现多子棋 ,可以任意切换想要玩的模式,还有在判断五子是否连成一线时,代码完成的比较粗糙,可以更加细化完成,再有电脑实现智能化下棋时,模式单一未能实现难易模式的转变等问题,有现在时间精力,及个人能力有限,暂时未能完成优化改进,相信在将来的学习中,随着知识的不断进步,也会将代码修改的更加优秀,如果有大佬看到我的文章,希望您多多 指点帮助,如果你也是刚刚接触C语言,那么我们一起学习进步!
敢于我的电脑较量五子棋么?相关推荐
- 五子棋c语言策划书活动内容,五子棋比赛策划书
与<五子棋比赛策划书>相关的范文 活动前言:楚汉相争,是智能的较量,让中国象棋带进我们进进那没有硝烟的战争中:谁先连珠,是智力的斗争,让五子棋带引我们走进那获胜的喜悦里.在棋类的对弈中,我 ...
- 编写五子棋程序时如何添加下棋时的音效_干货:如何提高编程能力
注意!!本文字数较多!都是干货! 很多初学者都会遇到各种各样的问题,比如下面这些类型的: 1.只会像高中一样跟着课程学习 2.怎么可以脱离课本和教学视频自己编写一个小项目? 3.停于理论,不知道如何实 ...
- c语言五子棋代码_基于控制台的C语言贪吃蛇
相信对很多人来说,学完C语言以后,都会找一些小程序来练练手.例如贪吃蛇.五子棋.俄罗斯方块等等. 今天给大家分享一个基于控制台的C语言贪吃蛇小程序. 基础知识要求:C语言基础. 知识点补充 这里写一些 ...
- python五子棋ai_零基础学Python之—AI五子棋(1)
今天是小编学习Python的第二天,有点小激动,因为我 昨天试了下水,做了一个Python的小弹球游戏,代码copy一路畅通,效果也还不错,而且,我居然还得了60个赞,很高兴,因为这是我第一次写技术博 ...
- Java小程序 —— 简单五子棋
看到好多后台留言问背景图片的问题,在这里统一补充一下:所有的图片都是读取的本地图片文件,图片文件可以去网上下载,有一大堆(记得调好长宽),代码中的路径只是当时我的电脑的图片路径,你们运行的时候记得修改 ...
- QT五子棋游戏课设及源码(连接mysql数据库含打开并运行程序的教程)
gdut大一下学期c++课设(得分:95) 实验报告及源码压缩包百度云下载: 链接:https://pan.baidu.com/s/1zO5ofMz09fiWihxCcZcFbg 提取码:ddav 首 ...
- 基于C的α-β剪枝算法实现的AI五子棋游戏
源码下载 http://www.byamd.xyz/hui-zong-1/ 对抗问题 对抗问题:顾名思义,博弈双方是带有对抗性质的.博弈的任何一方都希望局面尽量对自己有利,同时局面也应该尽量令对方不利 ...
- “果粉的倒戈”与荣耀的较量
十多年前,乔布斯演示第一代iPhone时说,"我们将重新定义手机",世界为之沸腾.从无到有,技术大胆创新,苹果迅速被推向浪潮之巅,手机战场格局为之改变. 不过,在瞬息万变的手机行业 ...
- 流量兄弟和站群软件的较量
流量兄弟和站群软件的较量 流量兄弟进入市场不长的时间以其迅猛的发展势头,迅速成为SEO行业的一把利刃,所向披靡,创造了一个又一个奇迹,让SEO行业迎来了新一轮的太阳. 今天我们就来说说这个软件 ...
最新文章
- Nginx学习之五:Nginx第三方模块
- mysql 触发器不能同时 insert or update or delete_运维日记|SQL server 那点事——DML触发器...
- 线程知识-ThreadLocal使用详解
- OpenCV中高斯混合背景建模算法汇总
- JAVA中List的几个方法
- 管理active directiory中的用户和计算机管理磁盘,IP多播桌面视频会议系统媒体流管理与安全机制的分析.pdf...
- 腾讯微博虽然停运,但其仍是一款成功的产品
- 王思聪名下企业被拍卖1100万债权,此前还债20亿 网友:拍下等于“接盘侠”?...
- 我的宽带是100兆,为什么到户只有30-50兆,我应该换成什么型号的路由器?
- delphi实现延时的方法,很多人首先就想到用timer控件,这里我们不用timer控delphi直接用settimer函数实现延时的方法...
- Ubuntu显卡驱动安装
- python DEA: 非径向距离函数(non-radial directional distance function)
- UE编辑器中的快捷键(一)
- a3967驱动_Arduino A3967 步进电机驱动板 EasyDriver Stepper Motor
- 设置word07标题样式
- 中国有多少家银行?(最全名单统计)
- 阿里云国际站代充值个人注册与分销商邀约区别
- 微信公众号如何推广运营
- 【CTF】咏春招新赛收获兼write up
- 对数字身份认证安全,是企业的责任还是个人的责任?
热门文章
- 2022最新考研资料
- 【巴比伦周报】2019第13周
- AQS中的公平锁和非公平锁
- 为何没有.aspx.designer.cs文件?
- 关于女生转行前端?细说这一年的心路历程..........
- 打造自己的ArchLinux系统---从安装到美化(一)
- Android Studio Run App 不能自动启动
- A brief introduction to MIMO
- 经验分享丨搭建积分兑换商城运营流程
- 用于语义分割的解码器 diffusion 预训练方法