C语言200行代码实现简易三子棋

news2024/12/27 11:18:30

在这里插入图片描述

前言

三子棋应该是是我们最早接触到的棋类游戏,用C语言实现三子棋对初学者来说是一种不错的锻炼
编写三子棋只需要用到数组、函数和生成随机数的知识,所以比较适合成为编程学习者编写的第一个小游戏。

一.代码实现

第一部分是源码复制就可以使用,每一个自定义函数在第二部分设计思路中都有详细解释,结合代码实现设计思路理解会有一个更好的效果

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
void reset(char arr[ROW][COL])//将棋盘arr[ROW][COL]数据赋值为空格
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			arr[i][j] = ' ';
		}
	}
}
void dis_play(char arr[ROW][COL])//打印棋盘
{
	for (int i = 0; i < ROW; i++)//for每一次进去,打印一行数组和一条分割线
	{	                         //数组行为:(空格)元素(空格)|(空格)元素(空格)|(空格)元素(空格)
		                         //分割线为: -      -      -   |   -      -     -   |   -     -      -
  		for (int j = 0; j < COL; j++)//一行数组
		{
			printf(" %c ", arr[i][j]);
			if (j < COL - 1)//为了美观,最后的“|”不打印
			{
				printf("|");
			}

		}
		printf("\n");
		for (int k = 0; k < COL; k++)//一行分割线
		{
			printf("---");
			if (k < COL - 1)//为了美观,最后的“|”不打印
			{
				printf("|");
			}

		}
		printf("\n");
	}

}

void player_move(char arr[ROW][COL])//玩家下棋
{
	int row = 0, col = 0;

	while (1)
	{
		printf("玩家下棋,请输入坐标>:");
		scanf("%d %d", &row, &col);
		if (arr[row - 1][col - 1] == ' ')//判断是否可以下棋
		{
			arr[row - 1][col - 1] = '*';
			break;
		}
		printf("输入错误,请再次输入\n");

	}
}



void computer_move(char arr[ROW][COL])//电脑下棋
{
	int row = rand() % ROW;//生成行号
	int col = rand() % COL;//生成列标
	printf("电脑下棋:>\n");
	while (1)
	{

		if (arr[row][col] == ' ')//判断是否可以下棋
		{
			arr[row][col] = '#';
			break;
		}
		row = rand() % ROW;
		col = rand() % COL;

	}
}
int is_full(char arr[ROW][COL])//用于在is_win()中判断是否为平局
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			if (arr[i][j] == ' ')
				return 0;
		}

	}
	return 1;
}

char is_win(char arr[ROW][COL])//三子棋胜利无非就三种情况:行相同、列相同和对角线相同。除开胜利还有平局
{
	for (int i = 0; i < ROW; i++)//判断行
	{
		if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
			return arr[i][0];
	}
	for (int i = 0; i < COL; i++)//判断列
	{
		if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[0][i] != ' ')
			return arr[0][i];
	}
	//判断对角线
	if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')
		return arr[0][0];
	if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[0][2] != ' ')
		return arr[0][2];

	//判断平局
	if (is_full(arr))
	{
		return 'q';
	}

	//都不满足游戏继续运行 return ‘c’
	return 'c';
}


void meau()
{
	printf("------------------\n");
	printf("|     1.play     |\n");
	printf("|----------------|\n");
	printf("|     0.exit     |\n");
	printf("------------------\n");
}

void game()
{
	char arr[ROW][COL];//初始化棋盘
	char ch;
	reset(arr);//将棋盘里每一个元素赋值为空格
	dis_play(arr);
	do
	{
		
		player_move(arr);
		dis_play(arr);
		ch=is_win(arr);
		if (ch != 'c')
		{
			break;
		}

		computer_move(arr);
		dis_play(arr);
		ch=is_win(arr);
		if (ch != 'c')
		{
			break;
		}
		
	} while (1);
	switch (ch)//根据返回字符判断结果
	{
	case '#':
		printf("电脑胜利\n"); break;
	case '*':
		printf("玩家胜利\n"); break;
	case 'q':
		printf("平局\n"); break;
	}
}

int main()
{
	srand((unsigned)time(NULL));
	int input = 0;
	do 
	{
		meau();
		scanf("%d", &input);
		switch (input)
		{
		case 1 :
			game(); break;
		case 0 :
			break;
		default :
			printf("输入错误\n");
		}
	} while (input);
	
	return 0;
}

二.设计思路

main()函数搭建框架

1.main()函数搭建框架:像所有的电脑游戏一样,我们需要一个菜单,通过菜单选择进入游戏和退出游戏,当一盘游戏结束时可以再次选择进入或者退出,菜单用printf()打印就可以解决,循环的进入游戏用do while()循环就可以解决

实现代码如下

 void meau()
    {
	  printf("------------------\n");
	  printf("|     1.play     |\n");
	  printf("|----------------|\n");
	  printf("|     0.exit     |\n");
	  printf("------------------\n");
    } 
    void game()
{
	·········
}
int main()
{
    

	int input = 0;
	do 
	{
		meau();
		scanf("%d", &input);
		switch (input)
		{
		case 1 :
			game(); break;
		case 0 :
			break;
		default :
			printf("输入错误\n");
		}
	} while (input);
	
	return 0;
}

2.当我们进入case 1,运行game()函数;首先我们需要一个容器来存放我们的游戏数据,此时创建字符二维数组arr[3][3]作为容器,玩家下的棋用“*”表示电脑用”#“表示。因为行和列都为3,后面经常要使用,我们对他进行宏定义一下
#define ROW 3
#define COL 3

dis_play( )函数

》.dis_play( ):我们下棋肯定需要棋盘来显示我们的数据,我们通过构造一个函数dis_play()将数组打印出来来实现这一功能

dis_play()的功能其实就是把arr[ROW][COL]以棋盘形式打印显示出来,需要借助一些特殊字符”|“和”_“辅助打印

#define ROW 3 / 行:3
#define COL 3 / 列:3
void dis_play(char arr[ROW][COL])
{
	for (int i=0;i<ROW;i++) /for每一次进去,打印一行数组和一条分割线
	{
		for (int j = 0; j < COL; j++)//打印数组
		{
			printf(" %c ", arr[i][j]);
			if (j < COL - 1)
			{
				printf("|");
			}
			
		}
		printf("\n");
		for (int k = 0; k < COL; k++)//打印分割线
		{
			printf("---");
			if (k < COL - 1)
			{
				printf("|");
			}
			
		}
		printf("\n");
	}
	
}

初步运行代码,打印棋盘:
在这里插入图片描述

reset ( )函数

reset ( ) :我们下完一盘棋,还想下该怎么办?这时候我们构造一个函数reset(),将棋盘数组的每一个元素重置为空格

reset()函数,遍历数组,赋值为空格

void reset( char arr[ROW][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			arr[i][j] = ' ';//赋值空格
		}
	}
}

player_move( )函数

player_move( ):玩家下棋,不能随便下,下过的地方不能下,我们构造一个player_move()函数完成这一功能

player_move( )函数功能其实就是为数组arr[ROW][COL]赋值,数组元素为空格的地方就是可以下棋的地方
输入坐标时,和我们程序员思维不同,正常人认为行是从1开始而不是从0开始,玩家输入的数据需要减1才能正常赋值

void player_move(char arr[ROW][COL])
{
	int row = 0, col = 0;
	
	while (1)
	{
		printf("玩家下棋,请输入坐标>:");
		scanf("%d %d", &row, &col);
		if (arr[row-1][col-1] == ' ')
		{
			arr[row-1][col-1] = '*';
			break;
		}
		printf("输入错误,请再次输入\n");
			
	}
}

玩家下棋
在这里插入图片描述

computer_move()函数

computre_move()电脑下棋,为了更容易实现我们这里让他再棋盘上随机下,需要生成随机数的知识,我们需要构造一个函数

使用头文件#include<stdlib.h>中的rand()函数可以生成一个0~32767的伪随机数,但使用rand()前先要使用srand()设置伪随机数起点
起点只要写一次,我们将srand((unsigned)time(NULL))定义在主函数,此处是一种固定的写法,time()函数需要引<time.h>头文件

将rand()%3即%ROW可以生产0、1、2这三个随机数,可以用来做数组的行号和列标

int main()
{
	srand((unsigned)time(NULL));/设置起点的固定写法
	int input = 0;
	do 
	{
		meau();
		scanf("%d", &input);
		switch (input)
		{
		case 1 :
			game(); break;
		case 0 :
			break;
		default :
			printf("输入错误\n");
		}
	} while (input);
	
	return 0;
}
void computer_move(char arr[ROW][COL])
{
	int row = rand() % ROW ;//利用随机数生成行号列标
	int col = rand() % COL ;
	printf("电脑下棋:>\n");
	while (1)
	{
		
		if (arr[row][col] == ' ')//判断是否为空格
		{
			arr[row][col] = '#';
			break;
		}
		row = rand() % ROW;
		col = rand() % COL;

	}
}

电脑下棋
在这里插入图片描述

is_win()函数

is_win()光下棋也不行,每当玩家或电脑下一步棋必须有东西来判断到底是玩家赢了还是电脑赢了还是平局还是继续,我们构造is_win()函数完成这一功能

is_win()函数功能最后是返回一个字符,电脑赢返回"#",玩家赢返回”*“,平局返回”q“,以上情况都不符合就返回”c“(continue)
三子棋胜利无非就三种情况:行相同、列相同和对角线相同我们用for和if语句就可以判断
平局的情况其实就是棋盘满了,我们构造一个is_fuii()函数,棋盘满了,该函数返回1否则返回0;

int is_full(char arr[ROW][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			if (arr[i][j] == ' ')/棋盘还有空格则return 0
				return 0;
		}

	}
	return 1;
}

char is_win(char arr[ROW][COL])  /is_win()函数
{
	for (int i = 0; i < ROW; i++)/判断是否有行相同
	{
		if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
			return arr[i][0];
	}
	for (int i = 0; i <COL; i++)/判断是否有列相同
	{
		if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[0][i] != ' ')
			return arr[0][i];
	}
	  /判断对角线是否相同
	if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')
		return arr[0][0];
	if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[0][2] != ' ')
		return arr[0][2];


	if (1==is_full(arr))/is_full()返回1return ‘q’
	{
		return 'q';
	}
		
		return 'c';/都不满足,return ‘c’
}

总结
整理不易,如果有帮助就来个三联吧,后续有时间我会改进这个代码

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

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

相关文章

WiFi(Wireless Fidelity)基础(六)

目录 一、基本介绍&#xff08;Introduction&#xff09; 二、进化发展&#xff08;Evolution&#xff09; 三、PHY帧&#xff08;&#xff08;PHY Frame &#xff09; 四、MAC帧&#xff08;MAC Frame &#xff09; 五、协议&#xff08;Protocol&#xff09; 六、安全&#x…

未面试蓄力,redis肝起来

目录 1、为什么要使用Redis做缓存&#xff1f;2、为什么Redis单线程模型效率也能那么高&#xff1f;3、Redis6.0为什么要引入多线程呢&#xff1f;4、Redis常见数据结构以及使用场景字符串&#xff08;String&#xff09;哈希(Hash)列表&#xff08;list&#xff09;集合&#…

【前端提效】--Chrome浏览器开发者工具 DevTools 使用技巧

介绍一下 DevTools 的一些好用的技巧&#xff0c;它能够很好地帮助你提高生产力和解决问题的能力。 1、打开命令行 或者使用&#xff1a;快捷键 Ctrl Shift P (Mac&#xff1a; ⌘ Shift P ) 命令行可以做很多事情&#xff0c;包括但不限于截图、更换主题等 2、控制 DevT…

Inno Setup Compiler的安装和使用详解

安装&#xff1a;官网最新下载最新版 最新版不支持中文哈&#xff0c;安装的时候直接选英文就好 安装注意事项&#xff1a;在安装过程中有一个 询问是否要 安装一个加密版本的&#xff08;可根据自己的需求挑选–我就没有&#xff09; 使用&#xff1a; 1.打开应用程序进入到…

【微信小程序】微信小程序的接口调入 获取太阳码 根据返回值的类型进行接收,微信接口可能直接返回图片,也可能返回一个错误信息的json,同时兼容处理这两种情况

目录 事件起因环境和工具操作过程解决办法遇到的一点问题结束语 事件起因 在开发一个关于微信小程序的过程中&#xff0c;有一个这样的需求&#xff0c;要求生成微信小程序的太阳码&#xff0c;然而这个东西的请求方式我们是这样的&#xff1a;我作为后端服务去请求这个太阳码…

【MFAC】基于紧格式动态线性化的无模型自适应控制(Matlab代码)

例题来源&#xff1a;侯忠生教授的《无模型自适应控制&#xff1a;理论与应用》&#xff08;2013年科学出版社&#xff09;。 &#x1f449;对应书本 4.2 单输入单输出系统(SISO)紧格式动态线性化(CFDL)的无模型自适应控制(MFAC) 例题4.1 题目要求 matlab代码 clc; clear al…

ASEMI代理ADXL345BCCZ-RL7原装ADI车规级ADXL345BCCZ-RL7

编辑&#xff1a;ll ASEMI代理ADXL345BCCZ-RL7原装ADI车规级ADXL345BCCZ-RL7 型号&#xff1a;ADXL345BCCZ-RL7 品牌&#xff1a;ADI /亚德诺 封装&#xff1a;LGA-14 批号&#xff1a;2023 安装类型&#xff1a;表面贴装型 引脚数量&#xff1a;14 工作温度:-55C~105C…

HTTPS连接建立过程

目录 前言什么是HTTPSHTTPS的作用 TLS建立连接过程1、TCP三次握手2、Client Hello3、Sever Hello4、校验数字证书5、客户端回应6、服务器回应7、TCP四次挥手 前言 什么是HTTPS HTTPS&#xff0c;Hyper Text Transfer Protocol over SecureSocket Layer&#xff0c;超文本传输…

「自动化」聊起来简单,做起来难 | 谈效风生

第4期&#xff1a;“自动化”聊起来简单&#xff0c;做起来难 在上一期《如何找到现有研发体系的「内耗问题」?》中&#xff0c;我们聊了评估现有研发体系&#xff0c;正确的找到“体系内耗问题”&#xff0c;是改变研发体系的第一步。本期我们继续聊下一个关键点就是研发体系…

MIT6.824 lab4B实验记录

Background 主要是完成一个可以根据group数量&#xff0c;动态调整shard所属的group的分布式kv键值引擎。其中shard->group的配置由shardctrler集群来管理&#xff0c;底层也是通过raft group来容错&#xff08;分布式嘛&#xff09; 然后这个shardkv就是要完成的是根据sh…

哪些地方能发表计算机论文? - 易智编译EaseEditing

计算机科学领域是一个快速发展的领域&#xff0c;每年都会涌现出许多新的科技和新的研究成果。 为了保证研究成果的质量和可信度&#xff0c;科学家们通常会通过期刊来发表自己的研究成果。 SCI期刊是世界著名的科技期刊数据库&#xff0c;被认为是科技领域内的权威数据库之一…

docker 系列之 Dockerfile 文件里 cmd命令与entrypoint命令区别

文章目录 一、cmd&#xff1a;用法1&#xff1a;带有中括号的形式用法2&#xff1a;shell form&#xff0c;即没有中括号的形式 二、entrypoint&#xff1a;第一种&#xff1a;命令行模式&#xff0c;也就是带中括号第二种&#xff1a;shell模式 三、总结&#xff1a; 一、cmd&…

《人月神话》纪念典藏版撤下了以前的宣传语

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>> 《人月神话》作者Frederick Phillips Brooks Jr. 于2022年11月17日逝世。 清华大学出版社近期将发行《人月神话》纪念典藏版。 新版的封底如下&#xff0c;宣传语更换成了…

CleanMyMac X4.13.2.dmg最新中文版下载

它是Mac上一款美观易用的系统优化清理工具&#xff0c;也是小编刚开始用Mac时的装机必备。它能够清理系统垃圾&#xff0c;提升电脑的运行速度&#xff0c;卸载许久不用的软件&#xff0c;使其变得如新机一般流畅。 CleanMyMac X是一款专业的Mac清理软件&#xff0c;可智能清理…

al智能改写工具-ai自动生成文章软件

随着互联网的发展&#xff0c;文章编辑在不断地向自动化、高效化方向进行转变&#xff0c;一款名叫“改稿神器”的工具应运而生。它可以帮助我们快速实现全自动批量改稿&#xff0c;做到没有错别字&#xff0c;自动优化语法&#xff0c;自动插入图片&#xff0c;严格按照标准的…

【腾讯云FinOps Crane 集训营】初识 FinOps Crane

前言&#xff1a; 有幸参加了腾讯云Finops Crane 集训营&#xff0c;学到了很多东西&#xff0c;现在将内容分享给大家。 Finops Crane &#xff1a;是一个基于 FinOps 的云资源分析与成本优化平台。 它的目标是希望在保证客户应用运行质量的前提下&#xff0c;实现极致的降本。…

web前端面试题汇总大全 -- 持续更新!

文章目录 一、html 系列 ⭐⭐⭐⭐⭐1、H5新增特性和css3新增特性&#xff1f; 二、css 系列 ⭐⭐⭐⭐⭐1、BFC的理解&#xff1f;2、说说你对盒模型的理解&#xff1f;3、如何实现元素⽔平垂直居中&#xff1f;4、CSS如何画⼀个三⻆形&#xff1f;原理是什么&#xff1f;5、说说…

二分查找基础篇-JAVA

文章目录 前言 大家好,我是最爱吃兽奶,这篇博客给大家介绍一下二分查找,我们先从最基本的开始讲解,再慢慢深入,把优化和变形也和大家说一下,那么,跟着我的步伐,我们一起去看看吧! 一、什么是二分查找? 二分查找(Binary Search)也称作折半查找 二分查找的效率很高,每查找一次…

Adam优化器及其变种的原理

本文将从SGD开始介绍Adam优化器的原理以及其变种的提出背景。 1、SGD的原理 SGD&#xff08;随机梯度下降法&#xff09;是基于最速梯度下降法的原理&#xff0c;假设我们存在损失函数&#xff0c;其中是要学习参数&#xff0c;定义如下的优化路径&#xff0c;使得损失函数值最…

Ray使用案例

Ray Use Cases Ray用例 本页索引了用于扩展ML的常见Ray用例。它包含了对博客、例子和教程的突出引用,也位于Ray文档的其他地方。 大型语言模型和生成型人工智能 大型语言模型(LLMs)和生成性人工智能正在迅速改变行业,并以惊人的速度要求计算。Ray为这些模型的扩展提供了…