C语言设计三子棋

news2024/12/29 9:39:41

引入

  谈到三子棋,大家应该都不陌生,学生时代我们大多人都爱拿作文本有事没事就跟同桌下两把,只要任意一方三点连成一线,就可以胜利。今天我作为一个计算机方面的博主,将会用C语言实现这个简单的小游戏(人机对战,电脑非智能)。由于三子棋是3*3的棋盘,所以我们主要要用到二维数组的有关知识点,该项目也是主要围绕二维数组来展开的。

基本框架

要实现这个简单的游戏,也需要实现不同的函数与结构,也要将不同部分放在不同源文件里,我们今天将会用(test.c-测试游戏的代码部分)和(game.c-游戏有关函数的实现),还有(game.h-游戏有关函数声明),下面我们来看一下这个游戏的框架。

首先我们先来看一下主函数的基本框架:

int main()
{
	int input = 0;//利用input来记录玩家的选择
	srand((unsigned int)time(NULL));//随机数时间戳设定,后面会用到
	do//设置循环使玩家在推出游戏前可多次选择再次游玩
	{
		menu();//打印一个基本的菜单,这里选择1.play(玩)或 0.exit(退出游戏)
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)//根据input进入不同选择
		{
		case 1:
			game();//选1直接进入游戏
			break;
		case 0:
			printf("退出游戏\n");//后面input也为0,在while(input)为假,结束程序
			break;
		default:
			printf("选择错误,请重新选择:>\n");
			break;
		}
	} while (input);
	return 0;
}

 下面我们来看一下game.h这个头文件,上面的思维导图也有讲,这里包含的是函数声明等内容,

game.c和test.c都会使用到,非常重要。

//所用库函数的头文件
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3//ROW即行数,定义为3
#define COL 3//COL即列数

//所需要函数的函数声明
void menu();
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);

然后我们来看一下这个游戏运行的大致逻辑,由test.c中的game()函数展示。

void game()
{
	char board[ROW][COL] = { 0 };//定义数组board,作为三子棋的主要框架
	Initboard(board,ROW,COL);//初始化二维数组(棋盘)
	Displayboard(board, ROW, COL);//打印棋盘
	char ret = 0;//这里定义字符类型ret,与后面判断输赢平有关
	while (1)//若未分胜负或者棋盘满了,则一直下,满足条件时跳出
	{
/*首先玩家下棋,然后展示一下棋盘,
然后利用Iswin函数判断输赢
(Iswin会返回一个字符,用ret接受,在后面进行判断)*/
		Playermove(board, ROW, COL);//玩家下棋函数
		Displayboard(board, ROW, COL);
		ret = Iswin(board, ROW, COL);
/*电脑下棋,方法同上*/
		Computermove(board, ROW, COL);//电脑下棋函数
		Displayboard(board, ROW, COL);
		ret = Iswin(board, ROW, COL);
//---为了更好地理解,这里先大致讲一下Iswin函数的大致逻辑。
//判断输赢,在玩家后者电脑每一次落子之后进行判断
//玩家赢 则返回'*'
//电脑赢 则返回'#'
//继续   则返回'C'
//平局   则返回'Q'
		if (ret != 'C')
			break;//如果未返回'C',跳出对战,对最终结果进行判断
	}
//最终结果的判断
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else if (ret == 'Q')
	{
		printf("平局\n");
	}
}

根据前面的内容,相信你一定了解了三子棋项目的大致逻辑,下面,我将对game()中所使用的所有函数,进行逐一讲解。

具体函数讲解

Initboard(初始化棋盘)函数:分析:棋盘是用来落子的,在程序中就是用来存放数据的,我们能自然而然地想到用二维数组来存放数据.

//参数说明:二维数组board,行数row,列数col。
void Initboard(char board[ROW][COL], int row, int col)
{
    //利用两个for循环对二维数组进行遍历,二维数组存放的数据都初始化为空格
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}
//这样就完成了棋盘的初始化

Display(打印棋盘)函数:分析:这个函数是这个项目的一个难点,磨刀不误砍柴工,首先让我们来看一下这个棋盘长什么样:

  

 可以看出,该棋盘是由“ %c | %c | %c ”与“---|---|---”交替连接而成的。我们可以将“ %c | %c | %c ”与“---|---|---”作为一个分割行的部分,当到达最后一行时,再少打印一个“---|---|---”,然后,我们再将“ %c |”和“---|”作为每一个分割列的部分,当到达最后一列时,两个部分都不打印“|”。

下面我们来看一下代码实现:

void Displayboard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < ROW; i++)
	{
		int j = 0;
		for (j = 0; j < COL; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < COL - 1)
				printf("|");
		}
		printf("\n");
		for (j = 0; j < COL; j++)
		{
			if (i < ROW - 1)
			{
				printf("---");
				if (j < ROW - 1)
					printf("|");
			}
			if (j == COL - 1)
				printf("\n");
		}
	}
}

 Playermove(玩家落子)函数:分析:这里主要记录玩家的落子,需要等待玩家输入要下的坐标。

这里主要要注意两点:1.玩家不是程序员,他输入的坐标肯定不是数组形式的(数组首元素从1开始),因此要注意输入坐标与数组元素的关系

2.注意坐标的合法性:应该需要有判断,判断坐标是否合法(输入坐标超出数组的实际范围,输入的坐标那里有其他内容),若不合法,则重新输入,所以外层应该还需要嵌套循环。

void Playermove(char board[ROW][COL], int row, int col)
{
	printf("玩家下棋\n");
	printf("请输入下的坐标:>");
	int i = 0, j = 0;
	while (1)
	{
		scanf("%d%d", &i, &j);
//输入坐标-1即为数组中对应坐标
		if ((board[i - 1][j - 1] != ' ')||(i - 1>ROW||j - 1>COL))
		{
			printf("输入坐标非法,请重新输入!");
		}
		else
		{
			board[i - 1][j - 1] = '*';//坐标合法,对应坐标落子'*'
			break;
		}
	}
}

Computermove(电脑落子)函数:分析:这里主要记录电脑的落子,需要电脑随机确定下的坐标。

注意:这里的电脑落子坐标需要随机,即需要rand()函数(在主函数中已经定义随机数时间戳,确保了完全随机),而且随机数可以指定范围,因此在落子合法性上不需要判断越界问题。

下面再来看一下代码实现。

void Computermove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");
	int i = 0;
	int j = 0;
	while (1)
	{
		i = rand() % ROW;//范围为(0-2)
		j = rand() % COL;//范围为(0-2)
		if (board[i][j] == ' ')
		{
			board[i][j] = '#';//输入坐标合法,落子为'#'
			break;
		}
	}
}

Iswin(判断输赢平)函数:分析:这里就运用到了三子棋的规则(三行其一或三列其一或主次对角线连成一线即可)。定义类型为char,上文也说过,该函数返回的字符有决策功能。

下面来看一下代码实现:

//Isfull是一个判断棋盘是否满了的辅助函数
int Isfull(char board[ROW][COL], int row, int col)
{
	int i = 0;
//对棋盘进行遍历
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//未满返回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[1][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[0][2] != ' ')
		return board[0][2];
    //利用Isfull判断棋盘是否满了,满了则平局
	if (Isfull(board, row, col) == 1)
	{
		return 'Q';
	}
	return 'C';
}

以上就是所有函数,下面我们来运行一下试试:

这里作者由于

太菜

输了。

好了,三子棋就分享到这,拜拜。

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

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

相关文章

sort命令 uniq命令 tr命令 cut命令

sort命令 ——以行为单位对文件内容进行排序&#xff0c;也可以根据不同的数据类型来排序 比较原则是从首字符向后&#xff0c;依次按ASCII码值进行比较&#xff0c;最后将他们按升序输出 语法格式&#xff1a; sort [选项] 参数 cat file | sort 选项 -n按照数字进行排序…

MySQL高可用之MHA集群

一、MHA概述 1.1 什么是 MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点故障的问题。 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。 MHA能在…

【模式识别9】python计算目标检测IoU、TP、FP、FN、Precision、Recall指标

python计算目标检测IoU、TP、FP、FN、Precision、Recall指标 1. 基础概念1.1 TP、TN、FP、FN1.2 IoU1.3 Precision&#xff08;P&#xff09;、Recall&#xff08;R&#xff09;、F1-score 2. python代码3. 总结 代码资源&#xff1a;IoU_P_R.py 1. 基础概念 1.1 TP、TN、FP、…

2023/5/14总结

哈夫曼树 哈夫曼树&#xff1a;给定n个权值作为n个叶子结点&#xff0c;构造一棵二叉树&#xff0c;若该树的带权路径长度&#xff08;WPL&#xff09;达到最小&#xff0c;则称该二叉树为哈夫曼树&#xff0c;也被称为最优二叉树。 怎样才能使带权路径长度最短&#xff1a;根据…

CTF-PHP反序列化漏洞5-反序列化字符逃逸

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。我的…

简单聊聊微前端

简单聊聊微前端 介绍微前端的优点应用间相互独立&#xff0c;互不依赖可以同时使用不同的技术栈可拓展性高可维护性更强&#xff0c;减少代码量提高开发和部署的效率团队的高度自主权错误隔离 微前端的缺点依赖项冗余CSS样式冲突和重叠性能比较差应用间的通信不够便捷 实现微前…

CSS的基础知识讲解

文章目录 一.什么是CSS二. 选择器2.1 标签选择器2.2 类名选择器2.3 ID选择器2.4 属性选择器2.5 子选择器2.6 后代选择器2.7 伪类选择器 三.盒子模型3.1 什么是盒子模型3.2 盒子的组成部分边框内边距外边距 四.弹性盒子布局4.1 什么是块级元素和行内元素块级元素行内元素行内元素…

◆ 前端工程化 ◆ webpack 的基本使用 ◆ webpack 中的插件 ◆ webpack 中的 loader ◆ 打包发布 ◆ Source Map

◆ 前端工程化 ◆ webpack 的基本使用 ◆ webpack 中的插件 ◆ webpack 中的 loader ◆ 打包发布 ◆ Source Map ◆ 前端工程化◆ webpack 的基本使用◆ webpack 中的插件◆ webpack 中的 loader1. loader 概述打包处理css文件打包处理less文件打包处理样式表中与url路径相关的…

Python——2

一、循环 1.range() 函数 用于生成一个整数序列&#xff0c;返回的是一个迭代对象&#xff0c;可用 in / not in查看。 &#xff08;1&#xff09;range(stop) 创建一个 [0,stop) 的整数序列&#xff0c;步长为1。 &#xff08;2&#xff09;range(start, stop) 创建一个 [s…

面试谎报了职级,本来是6,谎报成7,已经到HR这一步了,怎么了?

面试时谎报职级&#xff0c;公司能查出来吗&#xff1f; 一位网友说&#xff0c;自己在业务面时谎报了职级&#xff0c;把6报成7&#xff0c;现在已经到hr这一步了&#xff0c;该怎么办&#xff1f;是继续编吗&#xff1f; 有人不明白&#xff0c;为什么要谎报职级&#xff1f;…

Pycharm 安装教程,及常用快捷键,附教程

简介 PyCharm是一款Python IDE&#xff0c;其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如&#xff0c; 调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制等等。此外&#xff0c;该IDE提供了一些高级功能&a…

有史以来最强的5G入门科普!

一个简单且神奇的公式 今天的故事&#xff0c;从一个公式开始讲起。 这是一个既简单又神奇的公式。说它简单&#xff0c;是因为它一共只有3个字母。而说它神奇&#xff0c;是因为这个公式蕴含了博大精深的通信技术奥秘&#xff0c;这个星球上有无数的人都在为之魂牵梦绕。…

CloudCompare二次开发之如何配置PCL点云库?

文章目录 0.引言1.修改两个CMakeLists.txt文件2.源码编译3.测试PCL 0.引言 因笔者课题涉及点云处理&#xff0c;需要通过PCL进行点云数据分析处理&#xff0c;查阅现有网络资料&#xff0c;实现了VisualStudio2015(x86)配置PCL1.8.1点云库&#xff08;见&#xff1a;VisualStud…

基于卷积的图像分类识别(七):SENet

系列文章目录 本专栏介绍基于深度学习进行图像识别的经典和前沿模型&#xff0c;将持续更新&#xff0c;包括不仅限于&#xff1a;AlexNet&#xff0c; ZFNet&#xff0c;VGG&#xff0c;GoogLeNet&#xff0c;ResNet&#xff0c;DenseNet&#xff0c;SENet&#xff0c;MobileN…

网络编程 lesson3 UDP基础编程

目录 UDP介绍 UDP编程 函数接口 recvfrom sendto 小练习&#xff1a;实现服务器和客户端相连&#xff08;使用UDP实现&#xff09; client server UDP介绍 UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种在计算机网络中常用的传输…

C++常量成员函数(类成员函数后加const、类成员函数参数列表后加const)常量对象(类名前加const)和非常量对象

文章目录 常量对象和非常量对象&#xff08;常量对象不能调用非常量成员函数&#xff09;常量成员函数&#xff08;常量成员函数不能修改类的数据成员&#xff1b;常量成员函数只能调用常量成员函数&#xff0c;不能调用非常量成员函数&#xff09; 常量对象和非常量对象&#…

网络编程 lesson1 网络概念

目录 网络发展史&#xff08;了解&#xff09; 局域网和广域网 局域网 广域网 IP地址 IP地址划分&#xff08;IPV4&#xff09; IP地址取址范围&#xff1a; 特殊地址 子网掩码 子网号&#xff08;注意和前面进行区分&#xff09; 练习 练习1&#xff1a; 练习2&…

MySQL 数据库之 MMM 高可用架构构建

一、MMM 概述 1. 什么是 MMM   MMM&#xff08;Master-Master replication manager for MySQL&#xff0c;MySQL 主主复制管理器&#xff09;是一套支持双主故障切换和双主日常管理的脚本程序。MMM 使用 Perl 语言开发&#xff0c;主要从来监控和管理 MySQL Master-Master&a…

工厂模式中简单工厂模式、工厂方法模式、抽象工厂模式的分析与总结

工厂模式 工厂模式有许多变体,其中最常见的有三种 简单工厂模式工厂方法模式抽象工厂模式 简单工厂代码分析 UML图中我们可以清晰的看到代码结构 ,首先我们创建一个Car的汽车接口,定制汽车的基本规范,汽车可以的方法是可以跑,所以我们定义了一个抽象的run方法. 定义汽车接口…

【sed编辑器】

目录 一、sed编辑器二、sed的命令格式操作命令1.1、命令演示 二、替换三、插入 一、sed编辑器 1、sed是一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。 2、sed编辑器可以根据命令来处理数据流中的数据&#xff0c;这些命令要么…