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

news2024/11/14 14:53:05

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");
	else
		printf("平局\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");
	else
		printf("平局\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.coloradmin.cn/o/1940270.html

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

相关文章

开源模型应用落地-FastAPI-助力模型交互-进阶篇-RequestDataclasses(三)

一、前言 FastAPI 的高级用法可以为开发人员带来许多好处。它能帮助实现更复杂的路由逻辑和参数处理&#xff0c;使应用程序能够处理各种不同的请求场景&#xff0c;提高应用程序的灵活性和可扩展性。 在数据验证和转换方面&#xff0c;高级用法提供了更精细和准确的控制&#…

Springcloud之gateway的使用详解

官网地址&#xff1a;https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/ 1.网关入门 helloword 网关不依赖start-web 导入的pom&#xff1a; <!--gateway--> <dependency><groupIdorg.springframework.cloud</groupId><arti…

CKS-Kubernetes-证书题库总结

证书如下 个人考试总结 第一次考试 成绩如下&#xff0c;其实这一次我题目全做了&#xff0c;个人感觉也没有什么错误&#xff0c;但是环境做错了 7月14日CKS考试笔记 问题分析 你这次考试得了57%。 至少需要67%的分数才能通过。 对您完成的考试的自动分析显示了三个得分最…

【深度学习】起源:人脑的神经结构

文章目录 睁眼看世界&#xff0c;倾耳听人间脑子&#xff0c;是个好东西&#xff01;眼睛成像其它身体感触系统脑子&#xff1a;我很忙的&#xff01;脑细胞&#xff1a;脑子里的打工人生物神经元——结构生物神经元——人脑的运算单位 人脑的深度学习总结 睁眼看世界&#xff…

数据结构 —— B树

数据结构 —— B树 B树B树的插入操作分裂孩子分裂父亲分裂 我们之前学过了各种各样的树&#xff0c;二叉树&#xff0c;搜索二叉树&#xff0c;平衡二叉树&#xff0c;红黑树等等等等&#xff0c;其中平衡二叉树和红黑树都是控制树的高度来控制查找次数。 但是&#xff0c;这都…

李彦宏论AI:技术革新与产业价值的双重驱动

文章目录 每日一句正能量前言AI技术应用场景探索1. **医疗健康**2. **自动驾驶**3. **工业制造**4. **金融服务**5. **教育**6. **农业**7. **环境监测**8. **安全监控**9. **零售业**10. **艺术与娱乐** 避免超级应用陷阱的策略1. **明确应用目标**2. **优化用户体验**3. **注…

NFT革命:数字资产的确权、营销与元宇宙的未来

目录 1、NFT&#xff1a;数字社会的数据确权制度 2、基于低成本及永久产权的文化发现 3、PFP&#xff1a;从“小图片”到“身份表达”&#xff0c;再到社区筛选 4、透明表达&#xff1a;NFT 在数字化营销中的商业价值 5、可编程性&#xff1a;赋予 NFT 无限可能的应用 5.…

/秋招突击——7/21——复习{堆——数组中的第K大元素}——新作{回溯——全排列、子集、电话号码的字母组合、组合总和、括号生成}

文章目录 引言复习数组中的第K大的最大元素复习实现参考实现 新作回溯模板46 全排列个人实现参考实现 子集个人实现参考实现 电话号码的字母组合复习实现 组合总和个人实现参考实现 括号生成复习实现 总结 引言 昨天的科大讯飞笔试做的稀烂&#xff0c;今天回来好好练习一下&a…

git实操之线上分支合并

线上分支合并 【 1 】本地dev分支合并到本地master上 # 本地dev分支合并到本地master上# 远程(线上)分支合并# 本地dev分支合并到本地master上# 远程(线上)分支合并#####本地和线上分支同步################ #### 远程创建分支&#xff0c;拉取到本地####-远程创建分支&#…

服务攻防-应用协议cve

Cve-2015-3306 背景&#xff1a; ProFTPD 1.3.5中的mod_copy模块允许远程攻击者通过站点cpfr和site cpto命令读取和写入任意文件。 任何未经身份验证的客户端都可以利用这些命令将文件从文件系统的任何部分复制到选定的目标。 复制命令使用ProFTPD服务的权限执行&#xff0c;…

《2024 年 7 月 17 日最新开发者服务 API 推荐》

在当今的数字货币领域&#xff0c;对代币持有信息的精准洞察至关重要。而 Bitquery 代币持有信息查询 API 接口的出现&#xff0c;为开发者和投资者提供了强大的工具。无论是想要揭示代币趋势&#xff0c;检测虚假交易&#xff0c;发现热门代币&#xff0c;还是评估代币财富差距…

查找算法③-斐波那契查找算法/黄金分割查找算法

一、算法原理 斐波那契查找算法又称黄金分割查找算法&#xff0c;它是在二分查找基础上根据斐波那契数列进行分割的一种衍生算法&#xff0c;简单来说&#xff0c;二分查找是一分为二进行查找&#xff0c;斐波那契查找是使用斐波那契数列进行分割查找。而斐波那契数列就是我们通…

【Dison夏令营 Day 26】PyGame 中的赛车游戏

在本文中&#xff0c;我们将了解如何使用 Pygame 在 Python 中创建一个赛车游戏。在这个游戏中&#xff0c;我们将拥有驾驶、障碍物碰撞、通过关卡时速度增加、暂停、倒计时、记分牌和说明书屏幕等功能。 所需模块&#xff1a; 在继续之前&#xff0c;请在命令提示符下运行以下…

百科词条可以删除吗?删除百科词条的方法

大多时候大家都是想创建百度词条&#xff0c;然而有时候也会需要删除某些词条&#xff0c;因为其内容有错误、不实或者涉及某些敏感信息。但是百科词条删除需要非常明确的理由&#xff0c;不然也是很难通过的&#xff0c;这里小马识途百科顾问先初步分享下删除百科词条的流程。…

一套C#语言开发的医学影像归档与通讯系统PACS源码,三甲以下医院都能满足

医学影像归档与通讯系统&#xff08;PACS&#xff09;系统&#xff0c;是一套适用于从单一影像设备到放射科室、到全院级别等各种应用规模的医学影像归档与通讯系统。PACS集患者登记、图像采集、存档与调阅、报告与打印、查询、统计、刻录等功能为一体&#xff0c;有效地实现了…

Logstash docker发布

一 下载Logstash 不废话了&#xff0c;我下载的7.17.6 二 新增配置文件 在logstash/pipeline中&#xff0c;添加logstash.conf input {jdbc { # 连接jdbc_connection_string > "jdbc:mysql://192.168.1.1:3306/kintech-cloud-bo&#xff1f;characterEncodingUTF-8&…

【Linux网络】套接字编程

本篇博客整理了 socket 套接字编程的相关内容&#xff0c;包括 socket 网络通信原理、socket 相关的系统调用接口等&#xff0c;分别演示了基于UDP协议、TCP协议的 socket 网络编程&#xff0c;旨在让读者更加深入理解网络通信原理和设计&#xff0c;对网络编程有初步的认识和掌…

ECCV2024中有哪些值得关注的扩散模型相关的工作?

Diffusion Models专栏文章汇总:入门与实战 The Fabrication of Reality and Fantasy: Scene Generation with LLM-Assisted Prompt Interpretation 本文探讨了如何利用扩散模型生成需要艺术创造力或专业知识的复杂和富有想象力的图像提示。提出了一个新颖的评估框架RealisticF…

VulnHub:insomnia

靶机下载地址 信息收集 主机发现和端口扫描 攻击机网段192.168.31.0/24。 # 主机发现 nmap 192.168.31.0/24 -Pn -T4 # 靶机ip:192.168.31.207 端口扫描 nmap 192.168.31.207 -A -p- -T4 经过nmap扫描发现目标主机有http服务&#xff0c;端口是8080。 目录扫描 访问http…

Android RSA 加解密

文章目录 一、RSA简介二、RSA 原理介绍三、RSA 秘钥对生成1. 密钥对生成2. 获取公钥3. 获取私钥 四、PublicKey 和PrivateKey 的保存1. 获取公钥十六进制字符串1. 获取私钥十六进制字符串 五、PublicKey 和 PrivateKey 加载1. 加载公钥2. 加载私钥 六、 RSA加解密1. RSA 支持三…