【C语言】三子棋

 

前言:

三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏规则是双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利。但因棋盘太小,三子棋在很多时候会出现和棋的局面。

设计思路:

先开一个test.c文件用来进行游戏的逻辑测试,再开一个game.h头文件和game.c文件分别用来进行函数声明和实现游戏的逻辑,然后就是打印菜单、生成棋盘、实现玩家下棋、实现电脑下棋、判断游戏的输赢、游戏优化。

1. 打印菜单

test.c

void menu()
{
	printf("***************************\n");
	printf("********   1.play  ********\n");
	printf("********   2.exit  ********\n");
	printf("***************************\n");
}

int main()
{
	int input = 0;
	
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏.\n");
			break;
		default:
			printf("输入有误,请重新输入.\n");
		}
	} while (input);
	return 0;
}

2. 生成棋盘

2.1 初始化棋盘

我们可以用空格将每一个格子初始化。

test.c文件:

board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);

 game.c文件:

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] = " ";
		}
	}
}

其中的ROW和COL是两个宏定义。

 game.h

#define ROW 3
#define COL 3

2.2 打印棋盘

打印棋盘时我们可以一些符号隔开不同的空格,这样就会使我们的棋盘更加美观。比如我们可以使用“|”将同一行的空格分开,用“-”将不同行的空格分开,这样我们就可以得到一个如下的九宫格了。

 

 game.c文件:

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("   ");
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < row - 1)
		{
			for (int j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

 3. 实现玩家下棋和电脑下棋

为了游戏的可实行性,当玩家或电脑下完一个棋子后我们需要考虑以下两点:

1.玩家或电脑所下的坐标是否在棋盘的范围内。

2.玩家或电脑所下的位置是否已经被下过棋子了。

依据上面的两点条件的我们需要分别写一个条件语句,判断玩家是否合法下棋。

3.1 玩家下棋

game.c文件:

void PlayerMove(char board[ROW][COL], int row, int col)
{

	int x = 0, 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("坐标非法,请重新输入\n");
		}
	}
}

3.2 电脑下棋

思路: 

我们可以在让电脑生成随机数,这样就可以使其随机生成一个坐标下棋子,那么我们就可以简单的实现电脑下棋的效果了。

随机数的生成则可以使用rand函数、srand函数以及time函数。

game.c文件:

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:>\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % row;
		if (x <= row && x >= 1 && y <= row && y >= 1)
		{
			if (board[x][y] == ' ')
			{
				board[x][y] = '#';
				break;
			}
		}
		
	}
}

test.c文件:

srand((unsigned int)time(UNLL))

game.h文件:

#include<time.h>
#include<stdlib.h>

为了实现玩家下一个棋,然后电脑下一个棋的功能我们还需加上一个while循环。如下:

test.c文件:

while(1)
{
	//玩家下棋
	PlayerMove(board, ROW, COL);
	DisplayBoard(board, ROW, COL);
	//电脑下棋
	ComputerMove(board, ROW, COL);
	DisplayBoard(board, ROW, COL);
}

 4. 判断游戏的输赢

 思路:

此游戏无非只有三种结果:要么玩家赢,要么电脑赢,要么平局。所以我们可以写一个函数判断是这几种结果的哪一种,然后规定如果是玩家赢此函数返回“*”,如果是电脑赢则返回“#”,平局则返回“Q”,这几种都不是就说明游戏继续,那么就返回“C”.

要判断是否有赢的一方,无非就是判断是否出现了三个相同的棋子练成一条直线,而棋子连成的线无非就只有三种情况:竖线、横线、对角线。所以我们只需要判断是否出现了这三种情况的其中一种就可以了。而要判断是平局,则判断九宫格是否还有没有空格。

game.c文件:

int ItFull(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0;j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}
char ItWin(char board[ROW][COL], int row, int col)
{
	//行
	for (int i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][2] != ' ')
			return board[i][1];
	}
	//列
	for (int j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ')
			return board[1][j];
	}
	//对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != 0)
	{
		return board[1][1];
	}
	if (ItFull(board, row, col))
	{
		return 'Q';
	}
	return 'C';
}

test.c文件:

	//玩家下棋
	PlayerMove(board, ROW, COL);

	DisplayBoard(board, ROW, COL);
	//判断输赢
	char ret = ItWin(board, ROW, COL);
	if (ret != 'C')
	{
		if (ret == '*')
		{
			printf("玩家赢了!!!\n");
		}
		break;
	}
	//电脑下棋
	ComputerMove(board, ROW, COL);

	DisplayBoard(board, ROW, COL);
	//判断输赢
	ItWin(board, ROW, COL);
	if (ret != 'C')
	{
		if (ret == '#')
		{
			printf("电脑赢了!!!\n");
		}
		break;
	}

完整代码:

game.h文件:


#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define ROW 3
#define COL 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 ItWin(char board[ROW][COL], int row, int col);

test.c文件:

#include"game.h"

void menu()
{
	printf("***************************\n");
	printf("********   1.play  ********\n");
	printf("********   2.exit  ********\n");
	printf("***************************\n");
}
void game()
{
	//第一步打印棋盘。
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	char ret;
	while(1)
	{
		
		//玩家下棋
		PlayerMove(board, ROW, COL);

		DisplayBoard(board, ROW, COL);
		//判断输赢
		char ret = ItWin(board, ROW, COL);
		if (ret != 'C')
		{
			if (ret == '*')
			{
				printf("玩家赢了!!!\n");
			}
			break;
		}
		//电脑下棋
		ComputerMove(board, ROW, COL);

		DisplayBoard(board, ROW, COL);
		//判断输赢
		ItWin(board, ROW, COL);
		if (ret != 'C')
		{
			if (ret == '#')
			{
				printf("电脑赢了!!!\n");
			}
			break;
		}
	}
}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏.\n");
			break;
		default:
			printf("输入有误,请重新输入.\n");
		}
	} while (input);
	return 0;
}

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 j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void PlayerMove(char board[ROW][COL], int row, int col)
{

	int x = 0, 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("坐标非法,请重新输入\n");
		}
	}
}

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:>\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % row;
		if (x <= row && x >= 1 && y <= row && y >= 1)
		{
			if (board[x][y] == ' ')
			{
				board[x][y] = '#';
				break;
			}
		}
		
	}
}

int ItFull(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0;j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}
char ItWin(char board[ROW][COL], int row, int col)
{
	//行
	for (int i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][2] != ' ')
			return board[i][1];
	}
	//列
	for (int j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ')
			return board[1][j];
	}
	//对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != 0)
	{
		return board[1][1];
	}
	if (ItFull(board, row, col))
	{
		return 'Q';
	}
	return 'C';
}

运行图:

游戏优化: 

让电脑生成一个数的方式来实现一个电脑下棋的效果,肯定是没有什么可玩性的,等后面学习算法之后,我们就加入一些算法将其变为一个棋艺高超的棋手了。

以上就是使用c语言写三子棋的全部内容啦,如果上述内容对你有帮助的话不要忘记点上一个小小的赞和关注呦,期待我们下次再见。

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

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

相关文章

C++面试常见八股分享

1.unordered_set和set&#xff0c;unordered_map和map的区别 set 和 map 是 C STL 中的两种关联容器&#xff0c;而 unordered_set 和 unordered_map 是 C11 新增的基于哈希表的关联容器。它们之间的主要区别在于底层的数据结构和操作复杂度。 set 和 unordered_set&#xff1…

黑马程序员——接口测试——day05——Request库、Cookie、Session、UnitTest框架

目录&#xff1a; Requests库 Requests库安装和简介设置http请求语法应用案例 案例1案例2案例3案例4Cookie Cookie简介CookieSession认证方式案例5-看演示&#xff0c;此代码不需实现Session Session简介Session自动管理Cookie案例6面试题Cookie和Session区别获取指定响应数据…

云原生架构技术揭秘:探索容器技术的奥秘

云原生的概念和演进都是围绕云计算的核心价值展开的&#xff0c;比如弹性、自动化、韧性&#xff0c;所以云原生所涵盖的技术领域非常丰富。 随着云计算技术的不断发展&#xff0c;云原生架构已经成为了新一代软件开发的重要趋势。本文将为您介绍云原生架构的相关技术&#xf…

单片机精进之路-9ds18b20温度传感器

ds18b20复位时序图&#xff0c;先将b20的数据引脚拉低至少480us&#xff0c;然后再将数据引脚拉高15-60us&#xff0c;再去将测传感器的数据引脚是不是变低电平并保持60-240us&#xff0c;如果是&#xff0c;则说明检测到温度传感器&#xff0c;并正常工作。需要在240us后才能检…

鸿蒙真有前景吗?是真是假?

直到“纯血鸿蒙”发布&#xff0c;才看清华为真正的布局&#xff0c;这一招实在是高明&#xff01; “纯血鸿蒙”发布之前&#xff0c;国内大批人唱衰华为&#xff0c;唱衰鸿蒙系统的生态&#xff0c;认为大概率会走诺基亚和微软的老路&#xff0c;没想到“纯血鸿蒙”一经推出…

高质 智能 绿色低碳棒线材轧制 智能测径仪等亦起关键作用

第十一届棒线材会议围绕推动轧钢装备数字化、智能化、绿色化转型升级&#xff0c;实现高质量发展&#xff0c;高质量、智能化、绿色低碳主题&#xff0c;将于4月22-24日在贵州省六盘水市召开。这也是轧钢生产近几年的发展趋势。 在线棒材生产中&#xff0c;蓝鹏测控可提供三种类…

每天十条linux知识点-24-0226(1)

文章目录 1.在哪下载linux内核源码&#xff1f;2.linux文件夹都有哪些文件&#xff1f;arch&#xff1a;包含和硬件体系结构相关的代码&#xff0c;每种平台占一个相应的目录&#xff0c;如i386、arm、arm64、powerpc、mips等。block&#xff1a;块设备驱动程序I/O调度。certs&…

又降价啦!2024年腾讯云服务器优惠价格表,不看后悔!

腾讯云服务器多少钱一年&#xff1f;62元一年起&#xff0c;2核2G3M配置&#xff0c;腾讯云2核4G5M轻量应用服务器218元一年、756元3年&#xff0c;4核16G12M服务器32元1个月、312元一年&#xff0c;8核32G22M服务器115元1个月、345元3个月&#xff0c;腾讯云服务器网txyfwq.co…

高级语言期末2010级B卷(软件学院)

1.编写程序根据如下公式计算X的值&#xff08;精确到1e-5&#xff09;。 #include <stdio.h>int main(){int i1;double flag1.0/(2*i-1)*2.0*i/(2*i-1);double sum0;while(flag>1e-5){sumflag;i;flag1.0/(2*i-1)*2.0*i/(2*i-1);}printf("%lf",sum);return 0…

千兆单口(百兆双口)小体积 24PIN 网络变压器 H82409S 特点

Hqst华轩盛(石门盈盛)电子导读&#xff1a;千兆单口&#xff08;百兆双口&#xff09;小体积 24PIN 网络变压器 H82409S 特点 大家好&#xff0c;石门盈盛电子科技有限公司工程盛先生&#xff0c;今天向大家介绍石门盈盛电子科技有限公司的一款优势产品 - 千兆单口&#xff08;…

Docker(第四部分)

Docker微服务实战 通过IDEA新建一个普通微服务模块 把包放到linux机器里 pwd 通过dockerfile发布微服务部署到docker容器 dockerfile的内容 防火墙 Docker网络 网络主机 是什么&#xff1f; 网桥virbr0 常用基本命令 能干嘛 网络模式 最后都和u3一样了 结论&#xff1a;doc…

【Java程序设计】【C00329】基于Springboot的高校实习管理系统(有论文)

基于Springboot的高校实习管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的高校实习管理系统&#xff0c;本系统有管理员、公司、老师和学生四种角色&#xff1b; 管理员&#xff1a;个人中心、公司管理、…

故障排除:Failed to load SQL Modules into database Cluster

PostgreSQL 安装和故障排除 重新安装前的准备工作 在重新安装 PostgreSQL 之前&#xff0c;确保完成以下步骤&#xff1a; 重新卸载 PostgreSQL 并重启电脑。 删除以下目录&#xff1a; C:\Program Files\PostgreSQL\13C:\Users\admin\AppData\Roaming\pgadmin 重启安装过…

CentOS7——主机动态地址修改为静态地址

目录 1、查看本机的网络配置&#xff08;vmnet8网关&#xff09; 2、修改虚拟机主机网络信息配置文件 3、重启network服务使生效 4、测试 1、查看本机的网络配置&#xff08;vmnet8网关&#xff09; windows&#xff1a;“网络图标”——>“属性”——>“网络和共享中…

认识内部类

成员内部类 静态内部类 局部内部类 匿名内部类&#xff01;&#xff01;&#xff01;&#xff08;重点&#xff09; 匿名内部类在开发中常见的使用场景&#xff1a;通常作为一个参数传输给方法。

推荐系统经典模型YouTubeDNN代码

文章目录 前言数据预处理部分模型训练预测部分总结与问答 前言 上一篇讲到过YouTubeDNN论文部分内容&#xff0c;但是没有代码部分。最近网上教学视频里看到一段关于YouTubeDNN召回算法的代码&#xff0c;现在我分享一下给大家参考看一下&#xff0c;并附上一些我对代码的理解…

微信小程序真机调试:连接局域网失败ws://********:8001/失败,已切换回广域网模式的解决方式

这个问题大多数是由于系统上安装了虚拟网卡造成&#xff0c;只要禁用虚拟网卡即可查询方式&#xff1a;windx - 选择设备管理器 - 查看网络适配器&#xff0c;找到虚拟网卡禁用 重新勾选局域网模式进行调试即可

Go 互斥锁的实现原理?

Go sync包提供了两种锁类型&#xff1a;互斥锁sync.Mutex 和 读写互斥锁sync.RWMutex&#xff0c;都属于悲观锁。 概念 Mutex是互斥锁&#xff0c;当一个 goroutine 获得了锁后&#xff0c;其他 goroutine 不能获取锁&#xff08;只能存在一个写者或读者&#xff0c;不能同时…

Parallels Desktop安装虚拟机要执行此操作,您必须输入主机操作系统管理员认证凭据;执行该操作失败

弹窗1️⃣&#xff1a;执行此操作&#xff0c;您必须输入主机操作系统管理员认证凭据 桌面顶部点击《操作》点击《配置》 很多小伙伴在这一步又退回去重装了&#xff0c;其实不用&#xff0c;在配置里面设置就好了 弹窗2️⃣&#xff1a;执行该操作失败 设置如图&#xff1…

我写了个ImageWindow应用

文章目录 0 引言1 应用简介2 主要功能和特点2.1 多图像同/异步像素级对比2.2 支持多达30种图像格式2.3 高效率的图像处理性能 3 简明使用教程3.1 软件下载安装与更新3.1.1 软件下载与安装3.1.2 软件更新 3.2 多视窗添加并自动最优排列3.3 多样化图像导入方式3.4 自动切换显示模…