三子棋游戏的实现(C语言)

news2024/11/23 7:55:01

 三子棋游戏的实现,在这里我们要求满足:

  1. 游戏不退出,继续下一把(循环)
  2. 用多文件的形式实现,如下:
  • 用game.h文件存放函数的声明并包含需要的头文件
  • 用game.c文件存放各个函数的具体实现
  • 用test.c文件实现游戏的测试,运行

目录

一、游戏实现流程

二、功能的实现

1.创建菜单

2.创建棋盘并初始化

3、打印棋盘 

4、玩家下棋 

5、电脑下棋 

6、判断输赢 

三、代码汇总 

1、game.h文件 

2、game.c文件 

3、test.c文件 

四、游戏实现演示 

1、玩家赢 ​

2、电脑赢 

3、平局 ​

 


一、游戏实现流程

  1. 在菜单选择界面,选择开始或者退出游戏
  2. 创建棋盘并初始化
  3. 打印棋盘
  4. 玩家下棋
  5. 判断胜负
  6. 电脑下棋
  7. 判断胜负

二、功能的实现

1.创建菜单

为了让用户可以选择玩游戏还是退出游戏,我们要在test.c文件中实现创建菜单函数,代码如下:

void menu()
{
	printf("*********************************\n");
	printf("***********  1、play  ***********\n");
	printf("***********  0、exit  ***********\n");
	printf("*********************************\n");
}

2.创建棋盘并初始化

在这里我们用二维数组来实现棋盘的创建,代码如下:

#define ROW 3
#define COL 3
char board[ROW][COL] = { 0 };

这里使用了宏定义,提高了可扩展性,如果以后要修改棋盘的尺寸,我们直接修改宏定义的值即可

并且一开始将它初始化为空格,代码如下:

void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

3、打印棋盘 

我们要打印这样的棋盘:

可以使用循环, 将棋盘的行分为三组,列分为三组,如图:

但是打印最后一行时,没有"---|---|---"分界线,打印最后一列时,没有"|",所以我们要注意条件控制。代码如下:

void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		//1、打印数据
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		//2、打印分割线
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

4、玩家下棋 

在这里,玩家下棋为用字符 '*' 表示,我们通过玩家输入落子的坐标来实现下棋,那么我们就需要注意:

  1. 玩家输入的坐标是否合法(是否超出棋盘范围)
  2.  输入坐标合法的情况下,该坐标位置是否被占用

如果出现以上两种情况,玩家则重新输入坐标。代码如下:

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");
		}
	}
}

如发生,运行结果如下:

 在代码中我们判断坐标是否合法处用的是 if (x >= 1 && x <= row && y >= 1 && y <= col) ,x、y从1开始,因为对于玩家而言,棋盘就是从第一行第一列开始的,所以在下面判断棋盘是否被占用时,X和Y要减1(board[x - 1][y - 1])。

5、电脑下棋 

我们用字符 '#' 来表示电脑所下棋子,在这里电脑下棋是要产生随机值的,所以在主函数中我们要用到 srand((unsigned int)time(NULL)); 代码如下:

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

这里x = rand() % row,y = rand() % col 保证了电脑下棋产生的随机值在棋盘范围内。

6、判断输赢 

在判断输赢时,我们通过设计的字符函数的返回值来判断:

  • 返回 '*' 表示玩家获胜
  • 返回 '#' 表示电脑获胜
  • 返回 'Q' 表示平局
  • 返回 'C' 表示胜负未分,要继续游戏

在确定返回值时即判断输赢时,有以下几种情况:

  • 判断所有行
  •  判断所有列
  • 判断两对角线

代码如下:

char IsWin(char board[ROW][COL], int row, int col)
{
	//赢
	int i = 0;
	//行
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}

	}
	//列
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}

	}
	//对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0]!=' ')
	{
		return board[0][0];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//平局
	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

在平局的时候,棋盘被下满棋子,并且未分出胜负,我们用 int IsFull(char board[ROW][COL], int row, int col) 函数来判断棋盘是否被已满,代码如下:

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;
}

三、代码汇总 

1、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 IsWin(char board[ROW][COL], int row, int col);

2、game.c文件 

#include"game.h"
void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}
void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		//1、打印数据
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		//2、打印分割线
		if (i < row - 1)
		{
			for (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)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋>:\n");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
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)
{
	//赢
	int i = 0;
	//行
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}

	}
	//列
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}

	}
	//对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0]!=' ')
	{
		return board[0][0];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//平局
	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

3、test.c文件 

#include"game.h"

void menu()
{
	printf("*********************************\n");
	printf("***********  1、play  ***********\n");
	printf("***********  0、exit  ***********\n");
	printf("*********************************\n");
}
void game()
{
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	//下棋
	char ret = 0;
	while (1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		//电脑下棋
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);
	return 0;
}

四、游戏实现演示 

1、玩家赢 

2、电脑赢 

 3、平局 

这就是三子棋游戏的实现了,希望能对你有帮助呀!快来在自己电脑上实现它吧!

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

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

相关文章

【Linux】Keepalived+Haproxy实现数据库集群负载均衡

1、简介&#xff1a; 本文章的负载均衡和高可用是体现在两个从服务器上的。一般来说高可用是用在主服务器中的&#xff0c;例如双主多从的结构&#xff0c;双主做keepalived的高可用&#xff08;当然也可以加上haproxy做负载均衡&#xff09;&#xff0c;多从做haproxy的负载均…

微盟餐饮SaaS蜕变时刻:战略投资奥琦玮,领军之势已成

从火爆了整个春天的淄博烧烤&#xff0c;到“五一”人山人海的全国各地核心商圈&#xff0c;餐饮业热度狂飙不止。餐饮SaaS领域&#xff0c;大事件也在发生。 5月8日&#xff0c;微盟集团&#xff08;2013.HK&#xff09;宣布以“资产现金”方式&#xff0c;向餐饮行业数字化服…

前端get请求参数包含数组的情况

前端get请求参数包含数组的情况 问题描述解决办法文章参考 问题描述 当我们使用post传数组参数的时候&#xff0c;是没有问题的&#xff0c;可以不经过参数处理即可正常传参&#xff0c;但是当我们使用get请求传数组参数的时候&#xff0c;会出现下图这样的情况&#xff1a; a…

如何通过云平台加快Blender渲染?

Blender是一款专业自由及开放源代码的三维计算机图形软件&#xff0c;也是免费的开源3D创作套件&#xff0c;支持整个3D流程——建模、UV、贴图、材质、骨骼、动画、渲染、后期、合成、剪辑、跟踪和抠像等等&#xff0c;CG行业内也有不少大佬们通过Blender制作出了许多优秀作品…

代码随想录 LeetCode数组篇 螺旋矩阵II Java实现

文章目录 &#xff08;中等&#xff09;59. 螺旋矩阵II&#xff08;中等&#xff09;54. 螺旋矩阵&#xff08;简单&#xff09;JZ29 顺时针打印矩阵 &#xff08;中等&#xff09;59. 螺旋矩阵II 因为我是先做的JZ29&#xff0c;所以看到这题的时候&#xff0c;几乎就是一样的…

SpringCloud入门实战之项目(一)

一、新建父工程 以“下单”需要调“支付”模块为例&#xff0c;从零开始搭建springcloud-001项目&#xff0c;陆续集成相关组件。 新建服务提供者cloud-payment工程&#xff0c;服务调用者cloud-order工程&#xff0c;完成order对payment的调用。 只留下pom文件&#xff0c;其…

基于人工智能AI视频分析的智慧安监解决方案

方案背景 为了保证对园区环境风险进行有效识别&#xff0c;传统视频监控存在视频结构化利用率低的问题&#xff0c;在实际使用过程中&#xff0c;安全管理人员工作效率低下&#xff0c;依靠人工肉眼查看灵活度低&#xff0c;风险漏报概率高&#xff0c;出现异常情况跟踪不及时&…

中文润色神器-中文润色软件

中文写作润色软件 中文写作润色软件是一种基于自然语言处理技术和人工智能算法的工具&#xff0c;旨在提高中文文本的语言风格、表达能力和可读性。它可以自动检测文本中出现的语法、拼写、标点符号等语言问题&#xff0c;并给出相应的修正和修改建议。 中文写作润色软件的主…

paddleLite在Android部署初体验(环境问题)

paddleLite初体验&#xff08;环境问题&#xff09; Android Studio下载Paddle Lite Demo打开项目环境配置下载到手机 Paddle Lite是百度开发的一种方便部署的深度学习推理框架&#xff0c;笔者最近想接触一些模型部署相关项目&#xff0c;就先接触了一下Paddle Lite&#xff0…

手术麻醉信息系统源码 php + mysql + vue2,覆盖患者就诊全过程,体征数据自动采集绘制

手术麻醉信息系统源码 php mysql vue2 B/S网页版 麻醉信息系统是HIS产品的中的一个组成部分&#xff0c;主要应用于医院的麻醉科&#xff0c;属于电子病历类产品。医院麻醉监护的功能覆盖整个手术与麻醉的全过程&#xff0c;包括手术申请与排班、审批、安排、术前、术中和术…

list_for_each_entry()函数分析

在Linux内核源码中&#xff0c;经常要对链表进行操作&#xff0c;其中一个很重要的宏是list_for_each_entry&#xff1a; /*** list_for_each_entry - iterate over list of given type* pos: the type * to use as a loop cursor.* head: the head for your list.* member: t…

9个已开源的GPT4平替分享(附开源代码+论文)

资料整理自网络&#xff0c;有误欢迎指正 对于想要研究大模型的同学来说&#xff0c;目前ChatGPT无疑是最好的学习对象&#xff0c;但等它开源估计是不太可能了&#xff0c;所以学姐今天整理了一些开源的类GPT模型&#xff0c;帮助大家更好的理解大模型背后的机理。 PS&#x…

io,nio,aio区别

文章目录 前言io类型介绍同步阻塞io同步非阻塞ioio多路复用异步io 普通ionioChannelChannel实现基本的 Channel代码 示例 BufferBuffer的基本用法Buffer的capacity,position和limitcapacitypositionlimit Buffer的类型Buffer的分配向Buffer中写数据从Buffer中读取数据 Selector…

CSS 实现任意角度圆环

参考链接&#xff1a; css 制作圆环 - 掘金 主要思路&#xff1a; 利用 CSS 的 clip-path 属性进行裁剪 clip-path 具体信息参考 polygon() - MDN (mozilla.org) 该属性原理是&#xff1a;利用多边形进行对图形的裁剪。 根据具体代码&#xff0c;去分析 clip-path: polyg…

JavaWeb:Servlet、ServletContext、HttpServletResponse、HttpServletRequest 的详细内容

文章目录 JavaWeb - 02一、Servlet1. 简介2. HelloServlet3. Servlet 原理4. Mapping 原理 二、ServletContext1. 共享数据2. 获取初始化参数3. 请求转发4. 读取资源文件 三、HttpServletResponse1. 方法介绍2. 应用&#xff1a;下载文件3. 应用&#xff1a;创建验证码4. 应用&…

office web apps在线office文件预览部署及问题处理

文件下载链接网盘&#xff1a; 链接: https://pan.baidu.com/s/1OmWM5END0jyWESGzFCniEw 提取码: ejpg 基本环境需要两台机&#xff0c;1台为域控&#xff0c;1台为 &#xff08;office web apps &#xff0c;需要加入到域&#xff09; 主机1&#xff1a;添加域控服务 安装完…

设备树简介

设备树 设备树简介 设备树是一种描述硬件的数据结构&#xff0c;它起源于OpenFirmware&#xff08;OF&#xff09;。 在Linux 2.6中&#xff0c; ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx中&#xff0c;采用设备树后&#xff0c;许多硬件…

python操作字典

# 字典 score{"张三":"23","王五":"45"} print(score) dctdict(name张三,age20) print(dict) print(type(score)) # 字典元素的获取 print(score[张三]) print(score.get(张三)) # 判断是否是字典中的元素 print(王五 in score) # 为字…

浅析AI视频智能识别技术如何助力智慧平安校园建设

校园安全一直是学生健康成长、全面发展的前提与保障。校园门口伤害事件的频发与校园内应急事件的突发&#xff0c;让建设平安校园的任务愈加急迫。校园人流量大、监控点多&#xff0c;安保人员无法同时盯住上百个视频画面&#xff0c;亦无法保证24小时有效监控。传统的校园安防…