C语言实现三子棋游戏(可以改变为四子棋或者多子棋版)

目录

游戏介绍

游戏框架

游戏基本逻辑的介绍

游戏具体功能实现

初始化棋盘

打印棋盘

玩家下棋

电脑下棋

判断输赢

行和列:

对角线:

平局:

游戏继续:

游戏完整代码

test.c

game.c

game.h


游戏介绍

三子棋游戏或者说是井字棋游戏,相信大家都玩过,一般的流程就是在一个棋盘上,玩家下棋之后,电脑下棋,然后判断输赢,如果没输没赢,就再玩家下棋,电脑下棋。

游戏框架

对于这个小游戏来说,代码量还算少量,所以我们可以分为三个文件来写,养成好习惯,方便以后在公司好合作,所以我们就 test.c   game.c   game.h 三个文件:

test.c:用来写游戏的基本逻辑,包含打印菜单,游戏逻辑的展现。

game.c:最核心的代码部分,用来写游戏逻辑的实现,这部分一般不给别人看。

game.h:包含代码需要的头文件,函数定义,常量等。

游戏基本逻辑的介绍

我们首先要给玩家一个菜单,玩家才能选择是否开始游戏。我们需要上来就打印菜单,玩家再选择,所以我们使用do while 循环,在这个循环里需要一个选择语句,所以基本逻辑就是这样:

菜单:

这里玩家输入1 或者 0 ,就很妙,while循环()里放 input,输入1 就又开始循环,输出菜单,输入0 就结束循环了,退出游戏。

游戏具体功能实现

初始化棋盘

我们发现棋盘有行和列,这与我们的二维数组很相符,所以我们就定义一个二维数组来当棋盘

记住这个定义常量,这样我们就可以很方便的改变成多子棋之类的。

初始化棋盘只需要把二维数组里全部设为空格就行。

打印棋盘

我们的棋盘长什么样的:

所以我们需要打印这些分隔符。

玩家下棋

需要注意的点是:

1. 我们数组的下标是从0开始的,但是玩家下棋的话,他可能不知道下标从0开始,所以我们就需要自己操作一下。

2. 玩家下棋的坐标必须在棋盘内才能下,并且下的坐标必须没有棋子才行,所以需要判断。

电脑下棋

我们的电脑随机下棋,所以用rand 和 srand 函数。

判断输赢

判断输赢是这里比较复杂的地方,我们游戏有四种状态:1.玩家赢游戏结束 2.电脑赢游戏结束 3.游戏平局游戏结束 4. 游戏继续。 我们每次玩家下棋和电脑下棋都需要判断输赢,所以我们的函数返回:

行和列:

我们的输赢就是一行或者一列一样的就是谁赢了,有一行,一列的判断。例如:在一行中判断,要相互两个之间是一样的并且不是空格,那么flag就加一,只要flag 等于col -1 就说明赢了。

对角线:

除了行和列,我们还有对角线的判断:

看图我们就可以寻找到两条对角线的规律,依次写我们的代码。

平局:

我们遍历数组的所有元素如果有一个空格就不会平局,当一个也没有了就平局。

游戏继续:

如果以上都不是,就直接游戏继续。

特别提示:我们四种情况的返回字符也非常巧妙,当我们玩家赢和电脑赢的时返回的是他们下的棋子,这样我们就可以减少一些代码量了,不用单独判断一行或者一列是谁赢了。

游戏完整代码

test.c

#include"game.h"void meun()
{printf("********************\n");printf("****   1.  play  ***\n");printf("****   0.  exit  ***\n");printf("********************\n");
}void play()
{char ret = 0;//判断输赢的字符char board[ROW][COL];//初始化棋盘InitBoard(board, ROW, COL);//打印棋盘DisplayBoard(board, ROW, COL);while (1){//玩家下棋PlayerMove(board, ROW, COL);system("cls");//清空屏幕DisplayBoard(board, ROW, COL);ret = IsWin(board, ROW, COL);if (ret != 'A'){break;}//电脑下棋ComputerMove(board, ROW, COL);system("cls");printf("电脑下完棋了,该你了\n");DisplayBoard(board, ROW, COL);ret = IsWin(board, ROW, COL);if (ret != 'A'){break;}}if (ret == '*'){printf("玩家获胜\n");}else if (ret == '#'){printf("电脑获胜\n");}else{printf("平局\n");}
}int main()
{int input = 0;srand((unsigned int)time(NULL));do{meun();printf("请输入:");scanf("%d", &input);switch (input){case 1:play();break;case 0:printf("退出游戏\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);
}

game.c

#include"game.h"void InitBoard(char board[ROW][COL], int row, int col)
{for (int 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)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){//打印数据printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");//打印分隔符if (i < row - 1){for (int h = 0; h < col; h++){printf("---");if (h < col - 1){printf("|");}}}printf("\n");}
}void PlayerMove(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;while (1){printf("玩家输入坐标:");scanf("%d %d", &x, &y);if (x > 0 && x <= row && y > 0 && y <= col){if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("这个位置已被下了,重新输入\n");}}else{printf("坐标非法,请重新输入\n");}}
}void ComputerMove(char board[ROW][COL], int row, int col)
{//随机下棋while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}//对角线1
int Catercorner_diagonal_1(char board[ROW][COL], int row, int col)
{int flag = 0;for (int i = 0; i < row - 1; i++){if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' '){flag++;}}return flag;
}
//对角线2
int Catercorner_diagonal_2(char board[ROW][COL], int row, int col)
{int flag = 0;for (int i = 0; i < row - 1; i++){int j = col - 1;if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' '){flag++;}j--;}return flag;
}static int IsFull(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 IsWin(char board[ROW][COL], int row, int col)
{//判断行for (int i = 0; i < row ; i++){int j = 0;int flag = 0;//计算一行是否一样的标志for (j = 0; j < col - 1; j++){if (board[i][j] == board[i][j + 1]  && board[i][j] != ' '){flag++;}}if (flag == col - 1){return board[i][j];}}//判断列for (int j = 0; j < col; j++){int i = 0;int flag = 0;//计算一列是否一样的标志for (i = 0; i < row - 1; i++){if (board[i][j] == board[i + 1][j] && board[i][j] != ' '){flag++;}}if (flag == row - 1){return board[i][j];}}//判断对角线if (Catercorner_diagonal_1(board, ROW, COL) == row - 1){return board[0][0];}if (Catercorner_diagonal_2(board, ROW, COL) == row - 1){return board[0][col];}//判断平局if (IsFull(board, row, col)){return 'Q';}return 'A';
}

game.h

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<Windows.h>#define COL 3 //列
#define ROW 3 //行//初始化棋盘
void 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);//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
//玩家赢 返回*
//电脑赢 返回#
//平局  返回Q
//游戏继续 返回A

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

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

相关文章

浏览器不兼容的问题和通用解决方案

大家好&#xff0c;我是咕噜铁蛋&#xff0c;今天我想和大家聊聊一个在我们日常上网过程中经常遇到的问题——浏览器不兼容。这个问题看似微小&#xff0c;但却常常让我们在浏览网页、使用在线应用时感到困扰。接下来&#xff0c;我将详细分析浏览器不兼容的原因&#xff0c;并…

Vue2 —— 学习(八)

目录 一、浏览器 webStorage &#xff08;一&#xff09;介绍 &#xff08;二&#xff09;LocalStorage 1.存储数据 2.查询/读取数据 3.移除数据 4.清空数据 &#xff08;三&#xff09;SessionStorage 二、TodoList 案例使用 storage 三、组件的自定义事件 …

[lesson48]同名覆盖引发的问题

同名覆盖引发的问题 父子间的赋值兼容 子类对象可以当做父类对象使用(兼容性) 子类对象可以直接赋值给父类对象(<font color>兼容性)子类对象可以直接初始化父类对象父类指针可以直接指向子类对象父类引用可以直接引用子类对象 当使用父类指针(引用)指向子类对象时 子类…

30 消息队列

原理 操作系统可以通过页表映射在共享区创建一块共享内存&#xff0c;也可以申请一个队列。A进程和B进程可以向这个队列发送数据块&#xff0c;两个进程接收数据块来通信 函数 申请数据块 参数中的key来自于ftok函数 删除消息队列 同样消息队列也有数据结构管理&#xff…

数值分析复习:Richardson外推和Romberg算法

文章目录 Richardson外推Romberg&#xff08;龙贝格&#xff09;算法 本篇文章适合个人复习翻阅&#xff0c;不建议新手入门使用 本专栏&#xff1a;数值分析复习 的前置知识主要有&#xff1a;数学分析、高等代数、泛函分析 本节继续考虑数值积分问题 Richardson外推 命题&a…

解决在linux中执行tailscale up却不弹出验证网址【Tailscale】【Linux】

文章目录 问题解决提醒 问题 最近有远程办公需求&#xff0c;需要连接内网服务器&#xff0c;又不太想用todesk&#xff0c;于是找到一个安全免费可用的Tailscale Best VPN Service for Secure Networks&#xff0c;在windows中顺利注册账号后&#xff0c;登陆了我的windows …

上位机图像处理和嵌入式模块部署(树莓派4b进行驱动的编写)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 树莓派4b上面还支持驱动代码的编写&#xff0c;这是我没有想到的。这里驱动&#xff0c;更多的是一种框架的编写&#xff0c;不一定是编写真正的驱…

Python3中的JSON介绍

JSON的本质是一个字符串&#xff0c;有一些特定的格式。用途是每一种语言都可以实现数据传输&#xff0c;比如不同的编程语言之间的传输。 序列化&#xff1a;Python数据类型 -> JSON格式字符串 import json info {1: 2,2: 3 }string json.dumps(info) print(type(string…

20240422,C++文件操作

停电一天之后&#xff0c;今天还有什么理由不学习呜呜……还是没怎么学习 一&#xff0c;文件操作 文件操作可以将数据持久化&#xff0c;对文件操作时须包含头文件<fstream> 两种文件类型&#xff1a;文本文件&#xff1a;文件以文本的ASCII码形式存储&#xff1b;二进…

【Vue3】$subscribe订阅与反应

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

【深度学习总结_02】在自己的数据集微调SAM

【深度学习总结_02】在自己的数据集微调SAM 前言 SAM (Segment Anything Model)是Meta AI开发的一种分割模型。它被认为是计算机视觉的第一个基础模型。SAM是在包含数百万图像和数十亿mask的庞大数据语料库上进行训练的&#xff0c;这使得它非常强大。SAM能够为各种各样的图像…

代码随想录算法训练营第56天|583. 两个字符串的删除操作、72. 编辑距离

583. 两个字符串的删除操作 题目链接&#xff1a;两个字符串的删除操作 题目描述&#xff1a;给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 **相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 动态规划&#xff08;思路一&#xff09;&…

超越OpenAI,谷歌重磅发布从大模型蒸馏的编码器Gecko

引言&#xff1a;介绍文本嵌入模型的重要性和挑战 文本嵌入模型在自然语言处理&#xff08;NLP&#xff09;领域扮演着至关重要的角色。它们将文本转换为密集的向量表示&#xff0c;使得语义相似的文本在嵌入空间中彼此靠近。这些嵌入被广泛应用于各种下游任务&#xff0c;包括…

VideoComposer: Compositional Video Synthesis with Motion Controllability

decompose videos into three distinct types of conditions: textual conditions, spatial conditions, temperal conditions 条件的内容&#xff1a; a. textual condition: coarse grained visual content and motions, 使用openclip vit-H/14的text encoder b. spatial co…

Spring MVC的请求处理流程

Spring MVC的请求处理流程是一个精心设计的过程&#xff0c;旨在高效、灵活地处理Web请求并生成相应的响应。以下是该流程的详细解释&#xff1a; 用户发送请求&#xff1a; 用户通过浏览器或其他客户端发送HTTP请求到服务器。这个请求包含了请求的URL、请求方法&#xff08;如…

Splashtop 将在 NAB 展会上推出音视频剪辑增强功能

加利福尼亚州拉斯维加斯 Splashtop 在简化随处办公远程解决方案领域处于领先地位&#xff0c;在今年举行的 NAB 展会上将推出 Enterprise 解决方案的高级性能功能&#xff0c;均面向广播和媒体工作者而设计。 Splashtop Enterprise 经过优化&#xff0c;可为执行视频剪辑、唇…

Excel文件解析--超大Excel文件读写

使用POI写入 当我们想在Excel文件中写入100w条数据时&#xff0c;我们用普通的XSSFWorkbook对象写入时会发现&#xff0c;只有在将100w条数据全部加载入内存后才会用write()方法统一写入&#xff0c;这样效率很低&#xff0c;所以我们引入了SXSSFWorkbook进行超大Excel文件的读…

fixture固件和装饰器@pytest.mark.parametrize的参数化差异

fixture固件中有params参数可以进行参数化配置&#xff0c;装饰器pytest.mark.parametrize也可以为用例进行参数化配置&#xff0c;它们都是pytest框架中用于参数化测试的机制&#xff0c;但它们之间还是有很大差异的&#xff0c;该篇文章就来讲一讲这二者的区别使用&#xff1…

java开发之路——node.js安装

1. 安装node.js 最新Node.js安装详细教程及node.js配置 (1)默认的全局的安装路径和缓存路径 npm安装模块或库(可以统称为包)常用的两种命令形式&#xff1a; 本地安装(local)&#xff1a;npm install 名称全局安装(global)&#xff1a;npm install 名称 -g本地安装和全局安装…

C++中的STL——stack类的基本使用

目录 stack类介绍 stack类定义 stack类常见构造函数 stack数据操作 empty()函数 size()函数 top()函数 push()函数 pop()函数 swap()函数 stack类介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端…