三字棋游戏(C语言详细解释)

hello,小伙伴们大家好,算是失踪人口回归了哈,主要原因是期末考试完学校组织实训,做了俄罗斯方块,后续也会更新,不过今天先从简单的三字棋说起

话不多说,开始今天的内容


一、大体思路 

我们都知道,要做一个游戏,游戏菜单是必不可少的,所以首先我们要做一个开始的菜单

其次,我们知道三字棋,你菜单完了开始界面,棋盘是必不可少的,因此我们可以做一个棋盘

再次,有了棋盘就是玩家下棋和电脑下棋了,这里应该包含下棋位置的约束

之后还要有个功能判断输赢,之后就游戏结束

总体而言,包含如下流程:

游戏菜单:开始  /  离开

开始棋盘:初始化棋盘

玩家下棋:这里包括下棋位置是否合理

判断输赢:玩家赢  /  电脑赢  /  平局

电脑下棋:随机数的生成(如果让电脑玩家厉害一点,后续有时间我会补充)

判断输赢:玩家赢  /  电脑赢  /  平局

......

重复以上步骤,直到游戏结束

二、头文件与原文件的分类 

因为我用的是Visual Stdio 2022写的三字棋游戏,我是这么分配的

首先有个头文件 game.h 我用来放头文件和一些注释,函数声明,全局变量,这样的话,其它原文件就不用写头文件,只要包含一句 #include "game.h"就可以把头文件里面的内容包含进去

而针对于main函数,是写流程的,也能一下看清楚咱们的思路

其它函数功能我放在了另一个game.c的原文件里面,game.c原文件是专门写函数功能的

分配好这些,我们就可以详细的写代码了

 三、各个流程详细解释+代码

1.菜单(进入游戏+退出游戏)

首先游戏菜单我们要让游戏实现,开始或者离开,假如我们设定玩家输入 1 为开始游戏,进入游戏界面,输入 0 为离开游戏,游戏结束,那么我们只需要放到一个 while 循环里面就可以实现

而此时为了main函数简洁明了,我们选择用函数单另写一个菜单 menu();

//这里是game.c的原文件
#include "game.h"  //这句话只出现一次,后续再往进写东西我就不加这句话了
void menu()
{printf("————————————\n");printf("————1.enter ————\n");printf("————0.exit  ————\n");printf("————————————\n");printf("请输入你的选择:>");
}

此时参考代码如下:

//这里是main.c的原文件
#include "game.h"  //这句话只出现一次,后续再往进写东西我就不加这句话了
int main()
{while (1) {int c = 0;//游戏菜单menu();scanf("%d", &c);if (c == 0)//玩家输入0退出游戏break;else if (c == 1){game();//这里是三字棋游戏函数,之后要细写//玩家输入1进入游戏}}return 0;
}

别忘了头文件game.h的函数声明和头文件:

//这里是game.h头文件
#include <stdio.h>//游戏菜单
void menu();

2. 初始化棋盘

我们都知道,三字棋长这样,如下图:

首先棋盘是三行三列,因为我们就想到了二维数组

那么在没有 * 或者 # 的时候其它应该是空格,这就是我们初始化棋盘的原因

初始化我们需要将棋盘打印出来,因此还要写打印棋盘的函数

参考代码如下:

//这里是game.h头文件
#include <stdio.h>#define ROW 3 //棋盘的行数
#define COL 3 //棋盘的列数//游戏菜单
void menu();//初始化棋盘
void initboard(char board[ROW][COL], int row, int col);//打印棋盘
void displayboard(char board[ROW][COL], int row, int col);
//这里是main.c的原文件void game()
{char board[ROW][COL] = { 0 };initboard(board, ROW, COL);//初始化棋盘displayboard(board, ROW, COL);//打印棋盘
}
//这里是game.c的原文件
void initboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i <= ROW - 1; i++){for (int j = 0; j <= ROW - 1; j++){board[i][j] = ' ';}}
}void displayboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i <= ROW - 1; i++){for (int j = 0; j <= COL - 1; j++){printf(" %c ", board[i][j]);if (j <= COL - 2)printf("|");}printf("\n");if (i <= ROW - 2)printf("------------\n");}
}

给大家看一下我的棋盘效果,可以做个参考:

3.玩家下棋和电脑下棋

首先先理清我们的思路,写进main.c的原文件里

//这里是main.c的原文件​
void game()
{char board[ROW][COL] = { 0 };initboard(board, ROW, COL);//初始化棋盘displayboard(board, ROW, COL);//打印棋盘while (1) {playerboard(board, ROW, COL);//玩家下棋的函数displayboard(board, ROW, COL);//打印棋盘cpboard(board, ROW, COL);//电脑下棋的函数displayboard(board, ROW, COL);//打印棋盘}
}

之后再在头文件进行声明:

PS:电脑下棋,因为用到随机数rand();函数,这里要想时时刻刻都发生变化,那么就需要用到time函数,而这两个函数需要用到另外两个头文件 stdlib.h 和 time.h,我们一起加到game.h的头文件里,此时完整的game.h头文件如下

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 3
#define COL 3//游戏菜单
void menu();//初始化棋盘
void initboard(char board[ROW][COL], int row, int col);//打印棋盘
void displayboard(char board[ROW][COL], int row, int col);//玩家下棋
void playerboard(char board[ROW][COL],int row,int col);//电脑下棋
void cpboard(char board[ROW][COL], int row, int col);

玩家下棋,只要玩家输入横纵坐标在1~3即可,但是数组的三行是0~2,所以我们要注意数组的坐标要减一 

还要注意,玩家只能下在空格地方,也不能重复的下棋

电脑下棋,用随机数取余3,这样的话范围就在0~2,不会数组越界,因此这两个函数代码如下:

//这里是game.c的原文件
void playerboard(char board[ROW][COL],int row,int col)
{printf("玩家请下棋:>\n");int x = 0, y = 0;scanf("%d %d", &x, &y);while (1){if (x <= ROW && y <= COL && x >= 1 && y >= 1 && board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else if (board[x - 1][y - 1] != ' ' || x>ROW  || x<0 || y>COL || y<0 ){printf("坐标不合理,重新输入\n");scanf("%d %d", &x, &y);}}
}void cpboard(char board[ROW][COL], int row, int col)
{printf("电脑下棋:>\n");srand((unsigned int) time(NULL));int Row = 0, Col = 0;while (1) {Row = rand() % ROW;Col = rand() % COL;if (board[Row][Col] == ' '){board[Row][Col] = '#';break;}}
}

给大家展示一下效果,如下图:

4.判断输赢

这个时候有三种情况,那么不管谁每走一步,就要判断输赢,写个函数返回 * 就是玩家赢,返回 # 就是电脑赢,否则就是平局返回 Q ,没有分出胜负就返回 c 让游戏继续进行

大体思路代码如下:

//这里是main.c的原文件
void game()
{char board[ROW][COL] = { 0 };char ret = 0;initboard(board, ROW, COL);displayboard(board, ROW, COL);while (1) {playerboard(board, ROW, COL);displayboard(board, ROW, COL);ret = win(board, ROW, COL);if (ret != 'c')break;cpboard(board, ROW, COL);displayboard(board, ROW, COL);ret = win(board, ROW, COL);if (ret != 'c')break;}if (ret == '*')printf("玩家赢\n");else if (ret == '#')printf("电脑赢\n");elseprintf("平局\n");displayboard(board, ROW, COL);
}

在头文件进行声明:

//这里是game.h文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 3
#define COL 3//游戏菜单
void menu();//初始化棋盘
void initboard(char board[ROW][COL], int row, int col);//打印棋盘
void displayboard(char board[ROW][COL], int row, int col);//玩家下棋
void playerboard(char board[ROW][COL],int row,int col);//电脑下棋
void cpboard(char board[ROW][COL], int row, int col);//判断玩家赢
char win(char board[ROW][COL], int row, int col);

写出具体函数:

char win(char board[ROW][COL], int row, int col)
{int count = 0;for (int i = 0; i <= 2; i++){//行if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][1] != ' ')return board[i][1];}//列for (int j = 0; j <= 2; j++){if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')return board[1][j];}//对角if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[1][1] != ' ')return board[1][1];if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[1][1] != ' ')return board[1][1];for (int i1 = 0; i1 <= 2; i1++){for (int j1 = 0; j1 <= 2; j1++){if (board[i1][j1] == ' ')count++;}}if (count == 0)return 'Q';return 'c';
}

给大家展示我的效果:

这样的话一个三字棋就完成啦~

四、所有代码整理

顺序为game.h文件 -> main.c文件 -> game.c 文件

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 3
#define COL 3//游戏菜单
void menu();//初始化棋盘
void initboard(char board[ROW][COL], int row, int col);//打印棋盘
void displayboard(char board[ROW][COL], int row, int col);//玩家下棋
void playerboard(char board[ROW][COL],int row,int col);//电脑下棋
void cpboard(char board[ROW][COL], int row, int col);//判断玩家赢
char win(char board[ROW][COL], int row, int col);
#include "game.h"void game()
{char board[ROW][COL] = { 0 };char ret = 0;initboard(board, ROW, COL);displayboard(board, ROW, COL);while (1) {playerboard(board, ROW, COL);displayboard(board, ROW, COL);ret = win(board, ROW, COL);if (ret != 'c')break;cpboard(board, ROW, COL);displayboard(board, ROW, COL);ret = win(board, ROW, COL);if (ret != 'c')break;}if (ret == '*')printf("玩家赢\n");else if (ret == '#')printf("电脑赢\n");elseprintf("平局\n");displayboard(board, ROW, COL);
}int main()
{//游戏菜单while (1) {int c = 0;menu();scanf("%d", &c);if (c == 0)break;else if (c == 1){game();}}return 0;
}
#include "game.h"void menu()
{printf("————————————\n");printf("————1.enter ————\n");printf("————0.exit  ————\n");printf("————————————\n");printf("请输入你的选择:>");
}void initboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i <= ROW - 1; i++){for (int j = 0; j <= ROW - 1; j++){board[i][j] = ' ';}}
}void displayboard(char board[ROW][COL], int row, int col)
{for (int i = 0; i <= ROW - 1; i++){for (int j = 0; j <= COL - 1; j++){printf(" %c ", board[i][j]);if (j <= COL - 2)printf("|");}printf("\n");if (i <= ROW - 2)printf("------------\n");}
}void playerboard(char board[ROW][COL],int row,int col)
{printf("玩家请下棋:>\n");int x = 0, y = 0;scanf("%d %d", &x, &y);while (1){if (x <= ROW && y <= COL && x >= 1 && y >= 1 && board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else if (board[x - 1][y - 1] != ' ' || x>ROW  || x<0 || y>COL || y<0 ){printf("坐标不合理,重新输入\n");scanf("%d %d", &x, &y);}}
}void cpboard(char board[ROW][COL], int row, int col)
{printf("电脑下棋:>\n");srand((unsigned int) time(NULL));int Row = 0, Col = 0;while (1) {Row = rand() % ROW;Col = rand() % COL;if (board[Row][Col] == ' '){board[Row][Col] = '#';break;}}
}char win(char board[ROW][COL], int row, int col)
{int count = 0;for (int i = 0; i <= 2; i++){//行if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][1] != ' ')return board[i][1];}//列for (int j = 0; j <= 2; j++){if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')return board[1][j];}//对角if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[1][1] != ' ')return board[1][1];if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[1][1] != ' ')return board[1][1];for (int i1 = 0; i1 <= 2; i1++){for (int j1 = 0; j1 <= 2; j1++){if (board[i1][j1] == ' ')count++;}}if (count == 0)return 'Q';return 'c';
}

今天内容就到这里啦~希望大家有所收获 

 最后还是想和大家共勉,聊句心里话

因为我不是很聪明,所以才要比别人更努力!加油!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/874177.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MongoDB教程(十三):MongoDB覆盖索引

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言什么是覆盖…

数据结构(栈及其实现)

栈 概念与结构 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只允许在固定的⼀端进⾏插⼊和删除元素操作。 进⾏数据插⼊和删除操作的⼀端称为栈顶&#xff0c;另⼀端称为栈底。栈中的数据元素遵守后进先出 LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&…

PyCharm创建一个空的python项目

1.设置项目路径 2.配置python解释器 右下角可以选择always

【Linux】线程——生产者消费者模型、基于阻塞队列的生产消费者模型、基于环形队列的生产消费者模型、POSIX信号量的概念和使用

文章目录 Linux线程6. 生产消费者模型6.1 基于阻塞队列的生产消费者模型6.1.1 阻塞队列模型实现 6.2 基于环形队列的生产消费者模型6.2.1 POSIX信号量的概念6.2.2 POSIX信号量的使用6.2.3 环形队列模型实现 Linux线程 6. 生产消费者模型 生产消费者模型的概念 生产者消费者模…

Jackson详解

文章目录 一、Jackson介绍二、基础序列化和反序列化1、快速入门2、序列化API3、反序列化API4、常用配置 三、常用注解1、JsonProperty2、JsonAlias3、JsonIgnore4、JsonIgnoreProperties5、JsonFormat6、JsonPropertyOrder 四、高级特性1、处理泛型1.1、反序列化List泛型1.2、反…

Java 写一个可以持续发送消息的socket服务端

前言 最近在学习flink, 为了模仿一个持续的无界的数据源, 所以需要一个可以持续发送消息的socket服务端. 先上效果图 效果图 socket服务端可以持续的发送消息, flink端是一个统计单词出现总数的消费端,效果图如下 源代码 flink的消费端就不展示了, 需要引入一些依赖和版本…

Linux系统编程基础

Linux操作系统 Linux不是一个具体的操作系统&#xff0c;而是一类操作系统的总称&#xff0c;具体版本成为发行版。 Red Hat&#xff1a;目前被IBM收购&#xff0c;收费版&#xff0c;目前最大的Linux供应商CentOS&#xff1a; Red Hat退出的免费版Ubuntu&#xff1a;界面比较友…

二十一、【机器学习】【非监督学习】- 谱聚类 (Spectral Clustering)​​

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

hung 之 Android llkd

目录 1. llkd 简介 2. 原理 2.1 内核活锁 2.2 检测机制 2.3 为什么 persistent stack signature 检测机制不执行 ABA 检查&#xff1f; 2.4 为什么 kill 进程后&#xff0c;进程还存在就能判定发生了内核 live-lock&#xff1f; 3. 代码 3.1 内核 live-lock 检查 3.2 …

摸鱼大数据——用户画像——如何给用户“画像”

2、如何给用户“画像” 2.1 什么是标签体系 标签: 是某一种用户特征的符号表示 标签体系: 把用户分到多少类别里面去, 这些类是什么, 彼此之间有什么关系, 就构成了标签体系 标签解决的问题: 解决描述(或命名)问题以及解决数据之间的关联 2.2.1 标签的分类 用户画像标签一…

【附源码】IMX6U嵌入式Linux开发板连接阿里云--MQTT协议

演示 IMX6U嵌入式Linux开发板连接阿里云 阿里云创建设备&&获取LinkSDK 如果还不知道怎么在阿里云创建设备和获取连接阿里云的LinkSDK的话&#xff0c;先看这篇文章&#xff0c;再到这里。看这篇文章的时候&#xff0c;麻烦将下方文章打开对照着看&#xff0c;因为一些…

重测序数据处理得到vcf文件

重测序数据处理得到vcf文件 文章目录 重测序数据处理前言1. 数据是rawdata&#xff0c;需用fastp对数据进行质控和过滤2. 利用getorganelle软件组装叶绿体基因组3. 检查基因组大小&#xff0c;确认是否完整&#xff0c;然后和已知的红毛菜科叶绿体基因组一起构树4. 根据树形结果…

微积分-微分应用2(平均值定理)

要得出平均值定理&#xff0c;我们首先需要以下结果。 罗尔定理 设函数 f f f 满足以下三个假设&#xff1a; f f f 在闭区间 [ a , b ] [a, b] [a,b] 上连续。 f f f 在开区间 ( a , b ) (a, b) (a,b) 上可导。 f ( a ) f ( b ) f(a) f(b) f(a)f(b) 则在开区间 ( a , b …

CTFHUB-SQL注入-UA注入

目录 判断是否存在注入 判断字段数量 判断回显位置 查询数据库名 查询数据库下的表名 查询表中的字段名 查询字段名下的数据 由于本关是UA注入&#xff0c;就不浪费时间判断是什么注入了&#xff0c;在该页面使用 burp工具 抓包&#xff0c;修改User-Agent&#xff0c;加…

JavaScript之Web APIs-DOM

目录 DOM获取元素一、Web API 基本认知1.1 变量声明1.2 作用和分类1.3 DOM树1.4 DOM对象 二、获取DOM对象2.1 通过CSS选择器来获取DOM元素2.2 通过其他方式来获取DOM元素 三、操作元素内容3.1 元素.innerTest属性3.2 元素.innerHTML属性 四、操作元素属性4.1 操作元素常用属性4…

图形编辑器基于Paper.js教程09:鼠标拖动画布,以鼠标点为缩放中心进行视图的缩放

如何使用Paper.js实现画布的缩放与拖动功能 在Web开发中&#xff0c;利用Paper.js库进行图形的绘制和交互操作是一种常见的实践。Paper.js是一个强大的矢量图形库&#xff0c;可以让开发者通过简洁的API完成复杂的图形操作。在本文中&#xff0c;我们将详细探讨如何使用Paper.…

昇思25天学习打卡营第29天 | 基于MindSpore通过GPT实现情感分类

基于MindSpore框架通过GPT模型实现情感分类展示了从项目设置、数据预处理到模型训练和评估的详细步骤&#xff0c;提供了一个完整的案例来理解如何在自然语言处理任务中实现情感分析。 首先&#xff0c;环境配置是任何机器学习项目的起点。项目通过安装特定版本的MindSpore和相…

未来已来:生成式 AI 在对话系统与自主代理中的探索

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 一、整体介绍 对话系统&#xff08;Chat&#xff09; 自主代理&#xff08;Agent&#xff09; 二、技术对比 技术差异 优…

安装anaconda后jupyter notebook打不开 闪退

首先&#xff0c;通过清华源安装了最新的anaconda&#xff08;安装在了D盘&#xff09; 尝试打开jupyter&#xff0c;发现小黑框1s后自己关了&#xff0c;根本不打开浏览器 之后尝试按照这个做了一遍https://blog.csdn.net/gary101818/article/details/123560304还是不行。。…

【BUG】已解决:TypeError: Descriptors cannot not be created directly.

已解决&#xff1a;TypeError: Descriptors cannot not be created directly. 目录 已解决&#xff1a;TypeError: Descriptors cannot not be created directly. 【常见模块错误】 【错误原因】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来…