《如何使用C语言去下三子棋?》

目录

一、环境配置

二、功能模块

        1.打印菜单

2.初始化并打印棋盘

3、行棋 

        3.1玩家行棋

        3.2电脑行棋

4、判断是否和棋 

5.判赢

三、代码实现

        1、test.c文件

        2、game.c文件

        3、game.h文件


一、环境配置

        本游戏用到三个文件,分别是两个源文件test.c  game.c 和一个头文件game.h。

        主函数main()在test.c文件中,游戏实现所需要的函数在test.c中被引用,而函数的实现主要是在game.c文件中完成。game.h文件中包含了程序所需的所有头文件并且包括对实现游戏功能的所有函数的声明。

        之所以使用3个文件是因为,三子棋的实现需要多个模块的相互串联,多个文件各司其职,这样可以更好的处理各个模块间的逻辑,这样也增加了代码的可读性,而且还利于调试。

二、功能模块

1.打印菜单

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

  运行结果: 

 玩家选择(1/0)决定是否进入游戏。

 2.初始化并打印棋盘

InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
			
		}
		
	}
}
/* 通过创建一个char类型的二维数组对其进行初始化 */
char board[ ][ ] = { 0 };       
void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j;
	for (i = 0; i < row; i++)
	{
		j = 0; 
		for ( j; j < col; j++) //打印   |   |   
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		
		printf("\n");
		j = 0;
		for ( j; j < col; j++)//打印---|---|---
		{
			if (i < row - 1)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

 运行结果:

 其中,上述棋盘的大小可以根据用户需求自行调整。

 棋盘大小调整方式:在game.h文件中,对宏的定义进行更改即可完成棋盘大小的修改。

#define ROW 3
#define COL 3

3、行棋 

3.1玩家行棋

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int 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("坐标非法,请重新输入!");
		}
		
	}
}

3.2电脑行棋

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑走:>");
	while (1)
	{
		//生成随机坐标
		int x = rand() % row;
		int y = rand() % col;
		
		//下棋
		//判断坐标是否被占用
		if (board[x][y] == ' ')
		{
			printf("%d %d\n", x + 1, y + 1);//输出电脑下棋的坐标
			board[x][y] = '#';//电脑使用#下棋

			break;
		}
			
	}
}

         电脑和玩家每走一步棋,都会打印出新的棋盘,以便于玩家观察空子的位置。

4、判断是否和棋 

int IfFull(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;//棋盘满了
}

        在game.c文件中通过IfFull函数实现对棋盘上空位的判断,防止一个位置多次下棋。

        如果棋盘所有格子都下完之前,还没有分出胜负 ,则代表和棋,以上代码为判断棋盘上面是否有空格子。

5.判赢

char IfWin(char board[ROW][COL], int row, int col)
{
	//判断行
	for (int i = 0; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i][j - 2] == board[i][j - 1] && board[i][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断列
	for (int j = 0; j < col; j++)
	{
		for (int i = 2; i < row; i++)
		{
			if (board[i - 2][j] == board[i - 1][j] && board[i - 1][j] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断右交叉
	for (int i = 2; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i - 2][j - 2] == board[i - 1][j - 1] && board[i - 1][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断左交叉
	for (int i = 1; i < row - 1; i++)
	{
		for (int j = 1; j < col - 1; j++)
		{
			if (board[i - 1][j + 1] == board[i][j] && board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断平局
	int full = IfFull(board, row, col);
	if (full == 1)
	{
		return 'Q';
		
	}
	//游戏继续
	return 'C';
}

        每下一步棋,都会对棋盘的每行、每列、左交叉、右交叉做出判断,看是否有三个一样的旗子相连,如果有代表下棋者获胜,否则继续下棋,直至下满棋盘。

        return board[ i ][ j ] ;的奥妙之处就在于,无论是玩家获胜还是电脑获胜都会返回与其相同的棋子,不需要再重新进行判断取胜的棋子是哪一方,如果返回'*',证明玩家获胜,game()函数得到'*',判定玩家获胜,输出:“玩家获胜!”;如果返回'#',证明电脑获胜,game()函数得到'#',判定电脑获胜,输出:“电脑获胜!”

        如果通过IfFull()函数判断棋盘已经下满,就会给test.c文件中的game()函数中返回'Q’,game()函数得到'Q'便知道二者微分胜负,输出:和局。

        否则,return ’C',game()函数得到‘C’,游戏继续。

三、代码实现

1、test.c文件

#include"game.h"
char ret = 0;//ret用来存放比赛结果
void menu()
{
	
	printf("********************************\n");
	printf("*****        1.play        *****\n");
	printf("*****        0.exit        *****\n");
	printf("********************************\n");
}

void game()
{
	//存储数据 - 二维数组
	char board[ROW][COL];
	//初始化棋盘 - 初始化空格
	InitBoard(board,ROW,COL);
	//打印棋盘 - 本质是打印数组的内容
	DisplayBoard(board, ROW, COL);
	//玩家 电脑 走旗
	while (1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL); //打印玩家的每一步走棋
		//判断玩家是否赢得游戏
		ret = IfWin(board, ROW, COL);//玩家赢了*  电脑赢了#  平局Q  游戏继续C
		if (ret != 'C')
			break;
			
		//电脑下棋
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL); //打印电脑的每一步走棋
		//判断电脑是否赢得游戏
		ret = IfWin(board, ROW, COL);
		if (ret != 'C')
			break;
		
	}

	if (ret == '*')
	{
		printf("%c玩家获胜!\n", ret);

	}
	else if (ret == '#')
	{
		printf("%c电脑获胜!\n", ret);

	}
	else 
	{
		printf("%c     平局!\n", ret);
	}
	
	DisplayBoard(board, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//配合rand()函数生成随机值,因为只需要调用一次所以放到main()函数中
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("三子棋游戏\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}

	} while (input);
	return 0;
}

2、game.c文件

#include"game.h"

//初始化棋盘的函数
InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (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)
{
	int i = 0;
	int j;
	for (i = 0; i < row; i++)
	{
		j = 0; 
		for ( j; j < col; j++) //打印   |   |   
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		
		printf("\n");
		j = 0;
		for ( j; j < col; j++)//打印---|---|---
		{
			if (i < row - 1)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

//玩家下棋的函数
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int 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("坐标非法,请重新输入!");
		}
		
	}
}

//电脑下棋的函数
void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑走:>");
	while (1)
	{
		//生成随机坐标
		int x = rand() % row;
		int y = rand() % col;
		
		//下棋
		//判断坐标是否被占用
		if (board[x][y] == ' ')
		{
			printf("%d %d\n", x + 1, y + 1);//输出电脑下棋的坐标
			board[x][y] = '#';//电脑使用#下棋

			break;
		}
			
	}
}

//判断棋盘是否已经满了的函数
int IfFull(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 IfWin(char board[ROW][COL], int row, int col)
{
	//判断行
	for (int i = 0; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i][j - 2] == board[i][j - 1] && board[i][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断列
	for (int j = 0; j < col; j++)
	{
		for (int i = 2; i < row; i++)
		{
			if (board[i - 2][j] == board[i - 1][j] && board[i - 1][j] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断右交叉
	for (int i = 2; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i - 2][j - 2] == board[i - 1][j - 1] && board[i - 1][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断左交叉
	for (int i = 1; i < row - 1; i++)
	{
		for (int j = 1; j < col - 1; j++)
		{
			if (board[i - 1][j + 1] == board[i][j] && board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断平局
	int full = IfFull(board, row, col);
	if (full == 1)
	{
		return 'Q';
		
	}
	//游戏继续
	return 'C';
}

3、game.h文件

//头文件的包含
#include<stdio.h>
#include<stdlib.h>
#include<time.h>


//符号的定义
#define ROW 3
#define COL 3

//函数的声明

//初始化棋盘函数
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);
//判断游戏结果  玩家赢了*  电脑赢了#  平局Q  游戏继续C
char IfWin(char board[ROW][COL], int row, int col);
//判断棋盘是否已经下满
int IfFull(char board[ROW][COL], int row, int col);


感谢你的阅读,希望对你有所帮助~

欢迎批评指正,共同进步!

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

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

相关文章

排序算法之快速排序算法介绍

目录 快速排序介绍 时间复杂度和稳定性 代码实现 C语言实现 c实现 java实现 快速排序介绍 快速排序(Quick Sort)使用分治法策略。 它的基本思想是&#xff1a;选择一个基准数&#xff0c;通过一趟排序将要排序的数据分割成独立的两部分&#xff1b;其中一部分的所有数据…

动态规划——传球问题

题目链接&#xff1a;1.传球游戏 - 蓝桥云课 (lanqiao.cn) 本题关键在于动态规划的数组设计&#xff0c;以及围坐一圈时索引的变化。 首先是动态规划&#xff0c;由于是求球传递m次回到第一位同学&#xff0c;那么就可以设计成一个二维数组&#xff0c;每个位置代表的是&#x…

【LeetCode热题100】240. 搜索二维矩阵 II

一.题目要求 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 ‘每列的元素从上到下升序排列。 二.题目难度 中等 三.输入样例 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7…

蓝桥杯 填空 卡片

蓝桥杯 填空题 卡片 解题思路&#xff1a; 我们只需要消耗完卡片的个数即可。 代码示例&#xff1a; #include<bits/stdc.h> using namespace std; int a[10]; bool isEnd(){for(int i0;i<10;i){if(a[i]-1)return false;}return true; } bool getN(int x){while(x){i…

ARM 汇编指令:(五)CMP指令

目录 1.CMP比较指令 2.指令条件码 cond 1.CMP比较指令 CMP指令是计算机指令集中的一种比较指令&#xff0c;用于比较两个操作数的大小关系或相等性&#xff0c;并根据比较结果设置或更新条件码寄存器&#xff08;或程序状态字&#xff09;的标志位。 指令格式&#xff1a;C…

jenkins + gitea 自动化部署Docker项目(vue + .NET Core)

废话不多说&#xff0c;服务先安装好Jenkins 和 gitea 理论上 gitlab 一样的实现流程 Jenkins 配置&#xff1a; 第一步装插件 安装 Generic Event 安装 gitea 相关插件 创建一个任务 设置 git 根据自己git 的认证填写对应的认证方式 构建环境记得勾选这个&#xff0c;会清…

【关注】国内外经典大模型(ChatGPT、LLaMA、Gemini、DALL·E、Midjourney、文心一言、千问等

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

Python XML数据处理库之xmltodict使用详解

概要 在 Python 的开发中,处理 XML 数据是一项常见的任务。然而,Python 标准库中的 XML 解析器使用起来可能较为繁琐,需要编写大量的代码来处理 XML 数据。幸运的是,有一个名为 xmltodict 的第三方库可以帮助我们简化这个过程。本文将深入探讨 xmltodict 库的各个方面,包…

16、设计模式之观察者模式(Observer)

一、什么是观察者模式 观察者模式属于行为型模式。在程序设计中&#xff0c;观察者模式通常由两个对象组成&#xff1a;观察者和被观察者。当被观察者状态发生改变时&#xff0c;它会通知所有的观察者对象&#xff0c;使他们能够及时做出响应&#xff0c;所以也被称作“发布-订…

【git】GitHub仓库没有 Contribution activity

解决方案 检查并更改本地的 git 绑定的邮箱和名字 git config --global user.name "Your New Name" git config --global user.email "yournewemailexample.com"查询方式 git config --global user.name git config --global user.email成功显示

opencv dnn模块 示例(25) 目标检测 object_detection 之 yolov9

文章目录 1、YOLOv9 介绍2、测试2.1、官方Python测试2.1.1、正确的脚本2.2、Opencv dnn测试2.2.1、导出onnx模型2.2.2、c测试代码 2.3、测试统计 3、自定义数据及训练3.1、准备工作3.2、训练3.3、模型重参数化 1、YOLOv9 介绍 YOLOv9 是 YOLOv7 研究团队推出的最新目标检测网络…

Spring Cloud Alibaba微服务从入门到进阶(三)

Spring Cloud Alibaba是spring Cloud的子项目 Spring Cloud Alibaba的主要组件&#xff08;红框内是开源的&#xff09; Spring Cloud是快速构建分布式系统的工具集&#xff0c; Spring Cloud提供了很多分布式功能 Spring Cloud常用子项目 项目整合 Spring Cloud Alibaba …

开源导出html表格项目-easyHtml

开源导出html表格项目-easyHtml 背景介绍 背景 项目的由来&#xff0c;在面试的过程中&#xff0c;发现这个需求&#xff08;导出html表格&#xff09;比较常见&#xff0c;同时也引起我的兴趣&#xff0c;所以就有了开源项目easyHtml第一个版本 介绍 功能 支持自定义表格标…

Linux 配置ssh、scp、sftp免密登录

SSH&#xff08;Secure Shell&#xff09;是一种安全的远程登录协议&#xff0c;它使用客户端-服务器架构促进2个系统之间的安全通信&#xff0c;并允许用户远程登录服务器。在某些高可用环境下&#xff0c;服务器之间可能还需要配置免密互信&#xff0c;即基于密钥验证登录。 …

vue3 + antd二次封装a-table组件

前置条件 vue版本 v3.3.11 ant-design-vue版本 v4.1.1 内容梗概 二次封装a-table组件&#xff0c;大大提高工作效率和降低项目维护成本&#xff1b; 先看效果图 代码区域 utils.js文件 // 用于模拟接口请求 export const getRemoteTableData (data [], time 1000) >…

STM32第八节:位带操作——GPIO输出和输入

前言 我们讲了GPIO的输出&#xff0c;虽然我们使用的是固件库编程&#xff0c;但是最底层的操作是什么呢&#xff1f;对&#xff0c;我们学习过51单片机的同学肯定学习过 sbit 修改某一位的高低电平&#xff0c;从而实现对于硬件的控制。那么我们现在在STM32中有没有相似的操作…

【数据结构】Set的使用

文章目录 一、Set的使用1.Set的常用方法&#xff1a;1.boolean add(E e)2.void clear()3.boolean contains(Object o)4.boolean remove(Object o)5.int size()6.boolean isEmpty()7.Object[] toArray()8.boolean containsAll(Collection<?> c)9.boolean addAll(Collecti…

学习Vue(1)环境搭建与运行一个vue项目

下载node.js 下载地址&#xff1a;下载 | Node.js 中文网 安装 双击下载好的安装文件&#xff0c;选择安装路径即可。 安装完成&#xff0c;输入命令&#xff1a;nodel -v&#xff0c;查看版本&#xff0c;正常显示版本即安装成功。 自定义全局安装路径和缓存路径&#xff0…

SpringCloud-深度理解ElasticSearch

一、Elasticsearch概述 1、Elasticsearch介绍 Elasticsearch&#xff08;简称ES&#xff09;是一个开源的分布式搜索和分析引擎&#xff0c;构建在Apache Lucene基础上。它提供了一个强大而灵活的工具&#xff0c;用于全文搜索、结构化搜索、分析以及数据可视化。ES最初设计用…

用Origin快速拟合荧光寿命、PL Decay (TRPL)数据分析处理

需要准备材料&#xff1a;Origin、PL Decay数据txt文件 首先打开Origin画图软件 导入数据&#xff0c;按照下图箭头操作直接导入 双击你要导入的PL Decay的txt数据文件&#xff0c;然后点OK 继续点OK 数据导入后首先删除最大光子数之前的无效数据&#xff0c;分析的时候用…
最新文章