《如何使用C语言去下三子棋?》
目录
一、环境配置
二、功能模块
1.打印菜单
2.初始化并打印棋盘
3、行棋
3.1玩家行棋
3.2电脑行棋
4、判断是否和棋
5.判赢
三、代码实现
1、test.c文件
2、game.c文件
3、game.h文件
一、环境配置
本游戏用到三个文件,分别是两个源文件test.c game.c 和一个头文件game.h。
主函数main()在test.c文件中,游戏实现所需要的函数在test.c中被引用,而函数的实现主要是在game.c文件中完成。game.h文件中包含了程序所需的所有头文件并且包括对实现游戏功能的所有函数的声明。
之所以使用3个文件是因为,三子棋的实现需要多个模块的相互串联,多个文件各司其职,这样可以更好的处理各个模块间的逻辑,这样也增加了代码的可读性,而且还利于调试。
二、功能模块
1.打印菜单
void menu()
{printf("********************************\n");printf("***** 1.play *****\n");printf("***** 0.exit *****\n");printf("********************************\n");
}
运行结果:
玩家选择(1/0)决定是否进入游戏。
2.初始化并打印棋盘
InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (int j = 0; j < col; j++){board[i][j] = ' ';}}
}
/* 通过创建一个char类型的二维数组对其进行初始化 */
char board[ ][ ] = { 0 };
void DisplayBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j;for (i = 0; i < row; i++){j = 0; for ( j; j < col; j++) //打印 | | {printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");j = 0;for ( j; j < col; j++)//打印---|---|---{if (i < row - 1){printf("---");if (j < col - 1){printf("|");}}}printf("\n");}
}
运行结果:
其中,上述棋盘的大小可以根据用户需求自行调整。
棋盘大小调整方式:在game.h文件中,对宏的定义进行更改即可完成棋盘大小的修改。
#define ROW 3
#define COL 3
3、行棋
3.1玩家行棋
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("坐标非法,请重新输入!");}}
}
3.2电脑行棋
void ComputerMove(char board[ROW][COL], int row, int col)
{printf("电脑走:>");while (1){//生成随机坐标int x = rand() % row;int y = rand() % col;//下棋//判断坐标是否被占用if (board[x][y] == ' '){printf("%d %d\n", x + 1, y + 1);//输出电脑下棋的坐标board[x][y] = '#';//电脑使用#下棋break;}}
}
电脑和玩家每走一步棋,都会打印出新的棋盘,以便于玩家观察空子的位置。
4、判断是否和棋
int IfFull(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++){if (board[i][j] == ' '){return 0;//棋盘没满}}}return 1;//棋盘满了
}
在game.c文件中通过IfFull函数实现对棋盘上空位的判断,防止一个位置多次下棋。
如果棋盘所有格子都下完之前,还没有分出胜负 ,则代表和棋,以上代码为判断棋盘上面是否有空格子。
5.判赢
char IfWin(char board[ROW][COL], int row, int col)
{//判断行for (int i = 0; i < row; i++){for (int j = 2; j < col; j++){if (board[i][j - 2] == board[i][j - 1] && board[i][j - 1] == board[i][j] && board[i][j] != ' '){return board[i][j];}}}//判断列for (int j = 0; j < col; j++){for (int i = 2; i < row; i++){if (board[i - 2][j] == board[i - 1][j] && board[i - 1][j] == board[i][j] && board[i][j] != ' '){return board[i][j];}}}//判断右交叉for (int i = 2; i < row; i++){for (int j = 2; j < col; j++){if (board[i - 2][j - 2] == board[i - 1][j - 1] && board[i - 1][j - 1] == board[i][j] && board[i][j] != ' '){return board[i][j];}}}//判断左交叉for (int i = 1; i < row - 1; i++){for (int j = 1; j < col - 1; j++){if (board[i - 1][j + 1] == board[i][j] && board[i][j] == board[i + 1][j - 1] && board[i][j] != ' '){return board[i][j];}}}//判断平局int full = IfFull(board, row, col);if (full == 1){return 'Q';}//游戏继续return 'C';
}
每下一步棋,都会对棋盘的每行、每列、左交叉、右交叉做出判断,看是否有三个一样的旗子相连,如果有代表下棋者获胜,否则继续下棋,直至下满棋盘。
return board[ i ][ j ] ;的奥妙之处就在于,无论是玩家获胜还是电脑获胜都会返回与其相同的棋子,不需要再重新进行判断取胜的棋子是哪一方,如果返回'*',证明玩家获胜,game()函数得到'*',判定玩家获胜,输出:“玩家获胜!”;如果返回'#',证明电脑获胜,game()函数得到'#',判定电脑获胜,输出:“电脑获胜!”
如果通过IfFull()函数判断棋盘已经下满,就会给test.c文件中的game()函数中返回'Q’,game()函数得到'Q'便知道二者微分胜负,输出:和局。
否则,return ’C',game()函数得到‘C’,游戏继续。
三、代码实现
1、test.c文件
#include"game.h"
char ret = 0;//ret用来存放比赛结果
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);//玩家 电脑 走旗while (1){//玩家下棋PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL); //打印玩家的每一步走棋//判断玩家是否赢得游戏ret = IfWin(board, ROW, COL);//玩家赢了* 电脑赢了# 平局Q 游戏继续Cif (ret != 'C')break;//电脑下棋ComputerMove(board, ROW, COL);DisplayBoard(board, ROW, COL); //打印电脑的每一步走棋//判断电脑是否赢得游戏ret = IfWin(board, ROW, COL);if (ret != 'C')break;}if (ret == '*'){printf("%c玩家获胜!\n", ret);}else if (ret == '#'){printf("%c电脑获胜!\n", ret);}else {printf("%c 平局!\n", ret);}DisplayBoard(board, ROW, COL);
}int main()
{int input = 0;srand((unsigned int)time(NULL));//配合rand()函数生成随机值,因为只需要调用一次所以放到main()函数中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.c文件
#include"game.h"//初始化棋盘的函数
InitBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (int j = 0; j < col; j++){board[i][j] = ' ';}}
}//打印棋盘的函数
void DisplayBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j;for (i = 0; i < row; i++){j = 0; for ( j; j < col; j++) //打印 | | {printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");j = 0;for ( j; j < col; j++)//打印---|---|---{if (i < row - 1){printf("---");if (j < col - 1){printf("|");}}}printf("\n");}
}//玩家下棋的函数
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("坐标非法,请重新输入!");}}
}//电脑下棋的函数
void ComputerMove(char board[ROW][COL], int row, int col)
{printf("电脑走:>");while (1){//生成随机坐标int x = rand() % row;int y = rand() % col;//下棋//判断坐标是否被占用if (board[x][y] == ' '){printf("%d %d\n", x + 1, y + 1);//输出电脑下棋的坐标board[x][y] = '#';//电脑使用#下棋break;}}
}//判断棋盘是否已经满了的函数
int IfFull(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++){if (board[i][j] == ' '){return 0;//棋盘没满}}}return 1;//棋盘满了
}//判断游戏结果的函数
char IfWin(char board[ROW][COL], int row, int col)
{//判断行for (int i = 0; i < row; i++){for (int j = 2; j < col; j++){if (board[i][j - 2] == board[i][j - 1] && board[i][j - 1] == board[i][j] && board[i][j] != ' '){return board[i][j];}}}//判断列for (int j = 0; j < col; j++){for (int i = 2; i < row; i++){if (board[i - 2][j] == board[i - 1][j] && board[i - 1][j] == board[i][j] && board[i][j] != ' '){return board[i][j];}}}//判断右交叉for (int i = 2; i < row; i++){for (int j = 2; j < col; j++){if (board[i - 2][j - 2] == board[i - 1][j - 1] && board[i - 1][j - 1] == board[i][j] && board[i][j] != ' '){return board[i][j];}}}//判断左交叉for (int i = 1; i < row - 1; i++){for (int j = 1; j < col - 1; j++){if (board[i - 1][j + 1] == board[i][j] && board[i][j] == board[i + 1][j - 1] && board[i][j] != ' '){return board[i][j];}}}//判断平局int full = IfFull(board, row, col);if (full == 1){return 'Q';}//游戏继续return 'C';
}
3、game.h文件
//头文件的包含
#include<stdio.h>
#include<stdlib.h>
#include<time.h>//符号的定义
#define ROW 3
#define COL 3//函数的声明//初始化棋盘函数
InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘的函数
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断游戏结果 玩家赢了* 电脑赢了# 平局Q 游戏继续C
char IfWin(char board[ROW][COL], int row, int col);
//判断棋盘是否已经下满
int IfFull(char board[ROW][COL], int row, int col);
感谢你的阅读,希望对你有所帮助~
欢迎批评指正,共同进步!
相关文章:
《如何使用C语言去下三子棋?》
目录 一、环境配置 二、功能模块 1.打印菜单 2.初始化并打印棋盘 3、行棋 3.1玩家行棋 3.2电脑行棋 4、判断是否和棋 5.判赢 三、代码实现 1、test.c文件 2、game.c文件 3、game.h文件 一、环境配置 本游戏用到三个文件,分别是两个源文件test.c game.c 和…...
Linux——线程(4)
在上一篇博客中,我讲述了在多执行流并发访问共享资源的情况下,如何 使用互斥的方式来保证线程的安全性,并且介绍了Linux中的互斥使用的是 互斥锁来实现互斥功能,以及它的原理,在文章的结尾我提出了一个问题 用来引出同…...
vite+vue3项目中svg图标组件封装
一、安装插件 npm i vite-plugin-svg-icons -D 二、插件配置 // vite.config.jsimport { createSvgIconsPlugin } from "vite-plugin-svg-icons"; import path from "path";export default defineConfig({plugins: [// svg图标配置项createSvgIconsPlug…...
根据服务器系统选择对应的MySQL版本
1. 根据服务器系统选择对应的MySQL版本 MySQL有多个版本,选择对应的版本,重点信息是Linux的GLIBC版本号,Linux的版本、系统位数。 1.1 查看Linux的GLIBC版本号 通常libc.so会支持多个版本,即向前兼容,查看该文件中…...
【数据结构】栈与队列的“双向奔赴”
目录 前言 1.使用“栈”检查符号是否成对出现 2.使用“栈”实现字符串反转 3.使用“队列”实现“栈” 4.使用“栈”实现“队列” 前言 什么是栈? 栈(stack)是一种特殊的线性数据集合,只允许在栈顶按照后进先出LIFOÿ…...
sqllab第二十七关通关笔记
知识点: union select 关键字过滤 通过<> /**/进行截断处理 un<>ion sel<>ect 没效果uni/**/on sel/**/ect 被过滤了双写绕过 这关对select进行了多重过滤,无法进行双写绕过 大小写绕过 UNion SElect (这关可以用&am…...
助推直播产业升级与经济转型 天府锋巢直播产业基地成都开园
2023年年末,位于成都天府新区兴隆湖板块的天府锋巢直播产业基地正式开园,为成都直播产业注入了新的活力,助推成都经济转型和产业升级。天府锋巢直播产业基地的成立,不仅是成都直播产业的一大盛事,更是对成都经济发展的…...
VSCode+python单步调试库代码
VSCodepython单步调试库代码 随着VSCode版本迭代更新,在最新的1.87.x中,使用Python Debugger扩展进行调试时,扩展的justMyCode默认属性为true,不会进入库中的代码。这对debug而言不太方便,因此需要手动设置一下&#…...
如何使用EMC测试软件执行辐射抗扰度测试?(三)软件检查及手动模式
一、前言 之前的文章为大家介绍了使用EMC测试软件执行辐射抗扰度测试的测试方法、频率变化模式测试方法、校准方法及调制。本期文章继续为大家介绍软件检查和手动模式两部分内容。 前文回顾: 如何使用EMC测试软件执行辐射抗扰度测试?(一&am…...
云手机为电商提供五大出海优势
出海电商行业中,各大电商平台的账号安全是每一个电商运营者的重中之重,账号安全是第一生产力,也是店铺运营的基础。因此多平台多账号的防关联管理工具成了所有电商大卖家的必备工具。云手机最核心的优势就是账户安全体系,本文将对…...
chatgpt大模型基础学习
chatgpt大模型基础学习 1. 吴恩达提示工程2. 大模型说的token是什么 1. 吴恩达提示工程 知乎 https://zhuanlan.zhihu.com/p/626290417?utm_id0 中文版 https://mp.weixin.qq.com/s?__bizMzkwMjQ5MzExMg&mid2247483714&idx1&sn5e905f5ec6196f6dc2187db2a8618f02&…...
代码随想录算法训练营第14天 part01 | 二叉树理论基础篇
代码随想录 二叉树理论基础篇 二叉树的种类 二叉树有两种主要的形式:满二叉树和完全二叉树 满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。 这棵二叉树为满二叉树…...
async与defer的区别
原文解释 async vs defer attributes - Growing with the Web...
奇数乘积(C语言)
一、运行结果; 二、源代码; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值;int i 1;int j 3;//循环运算;while (j < 12){//运算;i i * j;//改变数值;j 2…...
中文分词库:jieba的词性对照表
jieba词性对照表 字母词性a形容词ad副形词ag形容词性语素an名形词b区别词c连词d副词dg副词素e叹词f方位词g语素h前接成分i成语j简称略称k后接成分l习用语m数词mq数量词n名词ng名词性语素nr人名ns地名nt机构团体名nz其他专名o拟声词p介词q量词r代词rg代词性语素rr人称代词rz指示…...
Linux:git的基础操作
git的下载 版本控制系统一般分为两种,集中式版本控制系统,分布式版本控制系统 什么是集中式版本控制系统:版本库集中存放在中央服务器,工作时候使用自己的电脑,当工作时候在中央服务器上拉取最新版本的代码,…...
【华为OD机试】CPU 算力分配【C卷|100分】
【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述 现有两组服务器A和B,每组有多个算力不同的CPU,其中 A[i] 是 A 组第 i 个CPU的运算能力, B[i] 是 B组 第 i 个CPU的运算能力。 一组服务器的总算力是各CPU的算力之和。 为了让两组服务器…...
挑战杯 机器视觉目标检测 - opencv 深度学习
文章目录 0 前言2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 0 前言 ǵ…...
基于Spring Boot的社区便民服务管理系统的设计与实现
摘 要 二十一世纪我们的社会进入了信息时代,信息管理系统的建立,大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多,而在线管理系统刚好能满足这些需求,在线管理系统突破了传统管理方式的局限性。于是本文针对这一…...
亚信安慧AntDB:数字化创新背后的数据力量
亚信安慧AntDB的“融合实时”的特性,不仅使得数据库具备了更强大的适应性,更让企业在不同业务场景下能够更好地实现业务目标,释放出更大的商业价值。融合实时的特性让AntDB具有了高度灵活性和实时性,使其能够满足企业在不同业务需…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...

