三字棋游戏(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");
	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.mfbz.cn/a/842877.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytest常用命令行参数解析

简介&#xff1a;pytest作为一个成熟的测试框架&#xff0c;它提供了许多命令行参数来控制测试的运行方式&#xff0c;以配合适用于不同的测试场景。例如 -x 可以用于希望出现错误就停止&#xff0c;以便定位和分析问题。–rerunsnum适用于希望进行失败重跑等个性化测试策略。 …

用ComfyUI安装可图Kolors大模型做手机壁纸

一、Kolors简介 国内科技公司快手在人工智能领域取得了显著进展&#xff0c;特别推出了「可图 Kolors」这一开源模型&#xff0c;它在图像生成质量上超越了SD3&#xff0c;与Midjourney v6模型相媲美&#xff0c;并支持中文提示词识别与生成中文字符&#xff0c;成为国产AI绘画…

经典神经网络(14)T5模型原理详解及其微调(文本摘要)

经典神经网络(14)T5模型原理详解及其微调(文本摘要) 2018 年&#xff0c;谷歌发布基于双向 Transformer 的大规模预训练语言模型 BERT&#xff0c;而后一系列基于 BERT 的研究工作如春笋般涌现&#xff0c;预训练模型也成为了业内解决 NLP 问题的标配。 2019年&#xff0c;谷歌…

Qt开发网络嗅探器03

数据包分析 想要知道如何解析IP数据包&#xff0c;就要知道不同的IP数据包的包头结构&#xff0c;于是我们上⽹查查资料&#xff1a; 以太网数据包 ARP数据包 IPv4 IPv6 TCP UDP ICMP ICMPv6 根据以上数据包头结构&#xff0c;我们就有了我们的protocol.h文件&#xff0c;声明…

node解析Excel中的考试题并实现在线做题功能

1、背景 最近公司安排业务技能考试&#xff0c;下发excel文件的题库&#xff0c;在excel里查看并不是很方便&#xff0c;就想着像学习驾考题目一样&#xff0c;一边看一边做&#xff0c;做完之后可以查看正确答案。 2、开始分析需求 题目格式如下图 需求比较简单&#xff0c;…

配置RIPv2的认证

目录 一、配置IP地址、默认网关、启用端口 1. 路由器R1 2. 路由器R2 3. 路由器R3 4. Server1 5. Server2 二、搭建RIPv2网络 1. R1配置RIPv2 2. R2配置RIPv2 3. Server1 ping Server2 4. Server2 ping Server1 三、模拟网络攻击&#xff0c;为R3配置RIPv2 四、在R…

ExoPlayer架构详解与源码分析(15)——Renderer

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

拖拽上传(预览图片)

需求 点击上传图片&#xff0c;或直接拖拽图片到红色方框里面也可上传图片&#xff0c;上传后预览图片 效果 实现 <!DOCTYPE html> <html lang"zh-cn"><head><meta charset"UTF-8"><meta name"viewport" content&…

【safari】react在safari浏览器中,遇到异步时间差的问题,导致状态没有及时更新到state,引起传参错误。如何解决

在safari浏览器中&#xff0c;可能会遇到异步时间差的问题&#xff0c;导致状态没有及时更新到state&#xff0c;引起传参错误。 PS&#xff1a;由于useState是一个普通的函数&#xff0c; 定义为() > void;因此此处不能用await/async替代setTimeout&#xff0c;只能用在返…

价格较低,功能最强?OpenAI 推出 GPT-4o mini,一个更小、更便宜的人工智能模型

OpenAI美东时间周四推出“GPT-4o mini”&#xff0c;入局“小而精”AI模型竞争&#xff0c;称这款新模型是“功能最强、成本偏低的模型”&#xff0c;计划今后整合图像、视频、音频到这个模型中。 OpenAI表示&#xff0c;GPT-4o mini 相较于 OpenAI 目前最先进的 AI 模型更加便…

51单片机(STC8H8K64U/STC8051U34K64)_RA8889驱动TFT大屏_I2C_HW参考代码(v1.3) 硬件I2C方式

本篇介绍单片机使用硬件I2C方式控制RA8889驱动彩屏。 提供STC8H8K64U和STC8051U34K64的参考代码。 【硬件部份】STC8H8K64U/STC8051U34K64 RA8889开发板 7寸TFT 800x480 1. 实物连接图&#xff1a;STC8H8K64URA8889开发板&#xff0c;使用P2口I2C接口&#xff1a; 2.实物连…

ISP代理和双ISP代理:区别和优势

随着互联网技术的不断发展和普及&#xff0c;网络代理服务成为众多用户保护隐私、提高网络性能、增强安全性的重要工具。其中&#xff0c;ISP代理和双ISP代理是两种常见的网络代理服务形式。本文将详细探讨ISP代理和双ISP代理的区别和优势&#xff0c;以便用户更好地了解并选择…

【LeetCode】填充每个节点的下一个右侧节点指针 II

目录 一、题目二、解法完整代码 一、题目 给定一个二叉树&#xff1a; struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NUL…

MySQL学习作业二

作业描述 SQL语言 建库&#xff0c;使用库 mysql> create database mydb8_worker;#新建库mysql> use mydb8_worker; 建表&#xff0c;查看表 #建表 mysql> create table t_worker(department_id int(11) not null comment部门号,worker_id int(11) primary key no…

Flink History Server配置

目录 问题复现 History Server配置 HADOOP_CLASSPATH配置 History Server配置 问题修复 启动flink集群 启动Histroty Server 问题复现 在bigdata111上执行如下命令开启socket&#xff1a; nc -lk 9999 如图&#xff1a; 在bigdata111上执行如下命令运行flink应用程序 …

使用IDEA编写lua脚本并运行

下载lua https://github.com/rjpcomputing/luaforwindows/releases 是否创建桌面快捷方式&#xff1a;我们的目标是使用IDEA编写lua脚本&#xff0c;所以不需要勾选。后面需要的话&#xff0c;可以到安装目录下手动创建快捷方式 环境变量自动配置 安装后会自动配置好环境变量…

影响转化率的多元因素分析及定制开发AI智能名片S2B2C商城系统小程序的应用案例

摘要&#xff1a;在互联网时代&#xff0c;转化率是衡量营销活动成功与否的关键指标。本文首先分析了影响转化率的多种因素&#xff0c;包括活动页面的设计、活动的限时性、主题文案的吸引力、从众心理的运用&#xff0c;以及最核心的产品质量与优惠力度。接着&#xff0c;本文…

PyTorch深度学习实战——使用深度Q学习进行Pong游戏

PyTorch深度学习实战——使用深度Q学习进行Pong游戏 0. 前言1. 结合固定目标网络的深度 Q 学习模型1.1 模型输入1.2 模型策略 2. 实现深度 Q 学习进行 Pong 游戏相关链接 0. 前言 我们已经学习了如何利用深度 Q 学习来进行 Gym 中的 CartPole 游戏。在本节中&#xff0c;我们将…

Redis之List列表

目录 一.列表讲解 二.列表命令 三.内部编码 四.应用场景 Redis的学习专栏&#xff1a;http://t.csdnimg.cn/a8cvV 一.列表讲解 列表类型是用来存储多个有序的字符串&#xff0c;如下所示&#xff0c;a、b、c、d、e五个元素从左到右组成了一个有序的列表&#xff0c;列表中的…

git使用、git与idea结合、gitee、gitlab

本文章基于黑马程序javase模块中的"git"部分 先言:git在集成idea中,不同版本的idea中页面显示不同,操作时更注重基于选项的文字;git基于命令操作参考文档实现即可,idea工具继承使用重点掌握 1.git概述 git是目前世界上最先进的分布式文件版本控制系统 分布式:将…