C语言—与坤(机)对弈

news2024/10/6 10:29:32

 

目录

设计思路

游戏运行效果 

函数的声明

头文件game.h

游戏主体(源文件)

1.game.c

2.test.c

各文件的阐述

各部分的设计心得

1.打印菜单

2.初始化棋盘

3.打印棋盘

棋盘最终效果

1.打印数据

2.打印分割线

如何扩展为10 x 10 棋盘?

4.玩家下棋、电脑下棋

玩家下棋

电脑下棋

5.游戏对局判断            

①玩家赢 / 电脑赢      

②平局           

       

③继续                        


设计思路

大体可以分为五个部分

1.打印菜单

2.初始化棋盘

3.打印棋盘

4.玩家下棋、电脑下棋

5.游戏对局判断

①玩家赢 / 电脑赢      

②平局                         

③继续                        

游戏运行效果 

函数的声明

头文件game.h

#pragma once


//三子棋游戏函数声明文件


#include<stdio.h>


#define COL 3
#define ROW 3

//打印菜单
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);

//判断平局
int IsFull(char Board[ROW][COL], int row, int col);

游戏主体(源文件)

1.game.c

#define _CRT_SECURE_NO_WARNINGS 1

//三子棋游戏主体

#include"game.h"
#include<time.h>




void InitBoard(char Board[ROW][COL], int row, int col)//初始化棋盘为空格
{
	int i = 0;
	int j = 0;
	for (i = 0; i < col; i++)
	{
		for (j = 0; j < col; j++)
		{
			Board[i][j] = ' ';
		}
	}
}




//打印棋盘
//版本1
//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]);
//		}
//			printf("\n");
//		}
//}




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



//版本3
void DisPlayBoard(char Board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//1. 打印数据
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", Board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");


		//2. 打印分割线
		if (i < row - 1)
		{
			int j = 0;
			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;
	int y = 0;
	printf("玩家下棋:>\n");

	while (1)
	{
		printf("请输入下棋坐标,中间使用空格:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= col && y >= 1 && y <= row)
		{
			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;
	for ( i = 0; i < row; i++)
	{
		int j = 0;
		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];
		}
	}

	int j = 0;
	for ( j = 0; j < col; j++)
	{
		//判断列
		if (Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j] && Board[0][j] != ' ')
		{
			return Board[0][j];
		}
	}

	//判断对角线
	if (Board[0][0] == Board[1][1] && Board[1][1] == Board[2][2] && Board[1][1] != ' ')
	{
		return Board[1][1];
	}
	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';




}

2.test.c

#define _CRT_SECURE_NO_WARNINGS 1

//三子棋测试文件

#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 flag = 0;
	while (1)
	{
		//玩家下棋
		PlayerMove(Board, ROW, COL);
		DisPlayBoard(Board, ROW, COL);
		//判断输赢
		flag = IsWin(Board, ROW, COL);
		if (flag != 'C')
		{
		break;
		}
	
		//电脑下棋
		ComputerMove(Board, ROW, COL);
		DisPlayBoard(Board, ROW, COL);
		//判断输赢
		flag = IsWin(Board, ROW, COL);
		if (flag != 'C')
		{
			break;
		}
	}
	
	
	//游戏结束
	if (flag == '*')
	{
		printf("玩家赢\n");
	}
	else if (flag == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}


}




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

各文件的阐述

game.h头文件用来声明函数
game.c游戏功能的实现
test调用game.c的函数,用于运行测试

各部分的设计心得

1.打印菜单

封装一个专门打印菜单的函数,后期想要美化菜单直接在函数修改即可,不用在海量的主体代码寻找菜单部分的代码,提高工作效率

2.初始化棋盘

三子棋需要一个3 x 3 的棋盘

故此我们需要一个三行三列的 二维数组

#define ROW 3

#define COL 3

char Board[ROW][COL] = {0};   

这里的定义在打印棋盘时有妙用 

void InitBoard(char Board[ROW][COL], int row, int col)//初始化棋盘为空格
{
	int i = 0;
	int j = 0;
	for (i = 0; i < col; i++)
	{
		for (j = 0; j < col; j++)
		{
			Board[i][j] = ' ';
		}
	}
}

3.打印棋盘

棋盘最终效果

分析上图  可以将棋盘拆分为两部分打印

void DisPlayBoard(char Board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//1. 打印数据
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", Board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");


		//2. 打印分割线
		if (i < row - 1)
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

1.打印数据

由于分割线为三个字符,故为了美观打印数据可以用空格补齐三个字符

在打印  |  时  需注意 其要比数据少打印一次

2.打印分割线

同理 在打印  |  时  需注意 其要比分割线少打印一次

注:上述打印棋盘操作以打印一行为例   故要嵌套循环 用外层循环来控制打印的行数

如何扩展为10 x 10 棋盘?

这是就体现了定义的好处了

可以通过修改定义来扩展棋盘

#define ROW 10

#define COL 10

char Board[ROW][COL] = {0};   

4.玩家下棋、电脑下棋

玩家下棋

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 <= col && y >= 1 && y <= row)
		{
			if (Board[x - 1][y - 1] ==' ')
			{
				Board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

以玩家的视角  棋盘坐标x,y的范围是1<x<3   1<y<3

而且数组的下标从0开始    故判断玩家是否可以落子时

将其输入的x,y坐标 横纵坐标均减  1   以此让计算机判断

电脑下棋

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

电脑下棋需要生成棋盘范围内的随机数

通过rand()可以生产随机数  需与srand()配合使用 

srand()只需要调用一次  故直接放在主函数即可

srand()与时间戳配合使用即可生成一个随机的生成器起点

srand(unsigned int(time(NULL)))

要将随机生成的数范围固定在棋盘内

通过取余的方法可以完成

x = rand() % row        得        0<x<row - 1

5.游戏对局判断            

①玩家赢 / 电脑赢      

三种情况

1.行

2.列

行列均可通过循环改变一个坐标 遍历所有行或列来判断

3.两条对角线

找出对角线坐标进行判断即可

返回赢家的下的棋子

②平局           

平局的判断在赢之后  即赢的判断无返回值才会进行平局判断

判断棋盘是否满了     满了即平局

return 'Q'

       

③继续                        

   return 'C'

注:返回值是一个巧妙的用法  因为赢的情况三个棋子都一样 

任意返回一个棋子的数据即可

在未来改变棋子的形状时也无影响

  ⠀⠰⢷⢿⠄
⠀⠀⠀⠀⠀⣼⣷⣄
⠀⠀⣤⣿⣇⣿⣿⣧⣿⡄
⢴⠾⠋⠀⠀⠻⣿⣷⣿⣿⡀
🏀 ⠀⢀⣿⣿⡿⢿⠈⣿
⠀⠀⠀⢠⣿⡿⠁⠀⡊⠀⠙
⠀⠀⠀⢿⣿⠀⠀⠹⣿
⠀⠀⠀⠀⠹⣷⡀⠀⣿⡄
⠀⠀⠀⠀⣀⣼⣿⠀⢈⣧                                       爱你们哟么么哒

⠀⠀ 

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

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

相关文章

mkv文件怎么转换成mp4?来看看这四种转换方式吧!

mkv文件怎么转换成mp4&#xff1f;在很多小伙伴看到&#xff0c;图片就是图片&#xff0c;音频就是音频&#xff0c;视频就是视频&#xff0c;它们展现给人们的效果都差不多。但实际上&#xff0c;不管是图片、视频还是音频文件&#xff0c;其中一个重要的区别在于它们的文件格…

照片尺寸怎么调整大小?三个方法,高效、快捷、安全!

照片尺寸怎么调整大小&#xff1f;照片是我们在日常生活和办公中经常会使用的文件类型之一。在制作各种文件、讲义、PPT、视频等内容时&#xff0c;图片都会成为重要的一部分。不同的图片格式和大小各有特点&#xff0c;有些图片虽然比较大但画质清晰&#xff0c;有些则方便传输…

选择排序,直接插入排序

目录 一、选择排序 1.基本思想 2.直接选择排序的流程 3.实验 二、直接插入排序法 1.基本思想 2.直接插入排序法的流程 3.实验 三、反向排序 1.实验 一、选择排序 与冒泡排序相比&#xff0c;直接选择排序的交换次数更少&#xff0c;所以速度会更快。 1.基本思想…

centos linux 配置私有网段并联网

文章目录 1. 创建虚拟机2. 虚拟机 A 配置网络3. 虚拟机 B 分配静态地址4. 测试 1. 创建虚拟机 vcenter 创建两台虚拟机A 、B&#xff0c;如何创建虚拟机请参考这里 虚拟机 A 具备两个网络接口&#xff0c;外网接口为 ens192 ip&#xff1a;192.168.22.6/20&#xff0c;网关为…

Golang tracing:与 OpenTelemetry、jaeger实现 跨服务 全链路追踪

使用 OpenTelemetry 链路追踪说明 工作中常常会遇到需要查看服务调用关系,比如用户请求了一个接口接口会调用其他grpc,http接口,或者内部的方法这样的调用链路,如果出现了问题,我们需要快速的定位问题,这时候就需要一个工具来帮助我们查看调用链路OpenTelemetry就是这样一个工…

Sui改进提案(SIPs)及其审核流程

SIPs提供了一个清晰透明的流程&#xff0c;使社区可以对Sui网络提出改进建议。 Sui基金会致力于打造一个开放协作的生态&#xff0c;因此推出了Sui改进提案&#xff08;SIPs&#xff0c;Sui Improvement Proposals&#xff09;&#xff0c;这是一个记录社区为去中心化未来的发…

如何利用API做好电商,接口如何凋用关键字

一.随着互联网的快速发展&#xff0c;电子商务成为了众多企业的首选模式&#xff0c;而开放API则成为了电商业务中不可或缺的部分。API&#xff08;Application Programming Interface&#xff09;&#xff0c;即应用程序接口&#xff0c;是软件系统不同组件之间交互的约定。电…

登录校验2.0

登录校验2.0 Filter Filter详解 过滤器Filter在使用中的一些细节&#xff0c;主要介绍一下3个方面的细节&#xff1a; 过滤器的执行流程过滤器的拦截路径配置过滤器链 执行流程 过滤器当中我们拦截到了请求之后&#xff0c;如果希望继续访问后面的web资源&#xff0c;就要…

内容编排与Kubernetes

第一节 内容编排与Kubernetes 为什么要用k8s 集群环境容器部署的困境&#xff0c;假设我们有数十台服务器。分别部署Nginx&#xff0c;redis&#xff0c;mysql&#xff0c;业务服务。如何合理的分配这些资源。这里就需要用到容器编排 容器编排 在实际集群环境下&#xff0…

线性结构-队列

队列是一种先进先出First In Fisrt Out,FIFO的线性表。 与一般的数组和链表不同&#xff0c;队列要求所有的数据只能从一端进入&#xff0c;从另一端离开。 输入进入的一端叫队尾rear&#xff0c;数据离开的一端叫队头front。 数据只能从队尾进入队列&#xff0c;从队头离开队…

VSCODE配置ROS编译环境

目录 一、安装插件 二、环境配置 2.1初始化工作空间 2.2配置VSCode 2.2.1创建功能包 2.2.2配置 c_cpp_properties.json 2.2.3配置 task.json 2.2.4配置 CMakeLists.txt 三、运行程序 3.1编译程序 3.2启动ros master 3.3执行可执行文件 用VSCode编辑ROS程序时&#xf…

linux 内核内存管理

物理内存 相关数据结构 page&#xff08;页&#xff09; Linux 内核内存管理的实现以 page 数据结构为核心&#xff0c;其他的内存管理设施都基于 page 数据结构&#xff0c;如 VMA 管理、缺页中断、RMAP、页面分配与回收等。page 数据结构定义在 include/linux/mm_types.h …

使用 Lambda 函数将 CloudWatch Log 中的日志归档到 S3 桶中

作者&#xff1a;SRE运维博客 博客地址&#xff1a;https://www.cnsre.cn/ 文章地址&#xff1a;https://www.cnsre.cn/posts/221205544069/ 相关话题&#xff1a;https://www.cnsre.cn/tags/aws/ 躺了好久&#xff0c;诈尸了。因为换了工作&#xff0c;所以比较忙一直没有时间…

解决APP抓包问题「网络安全」

1.前言 在日常渗透过程中我们经常会遇到瓶颈无处下手&#xff0c;这个时候如果攻击者从APP进行突破&#xff0c;往往会有很多惊喜。但是目前市场上的APP都会为防止别人恶意盗取和恶意篡改进行一些保护措施&#xff0c;比如模拟器检测、root检测、APK加固、代码混淆、代码反调试…

挖出api接口的重要性

作为一名软件开发者&#xff0c;API是我们工作中不可或缺的一部分。无论是将不同系统连接起来&#xff0c;还是构建多组件应用程序&#xff0c;API都是我们的核心工具之一。在本文中&#xff0c;我们将深入讨论API的技术细节和实际应用。 一.首先&#xff0c;我们来看看什么是…

怎么把mkv格式改成mp4?不妨试试这几种方法吧!

怎么把mkv格式改成mp4&#xff1f;mp4是一种多媒体封装格式&#xff0c;不过我们通常会将它说成是视频格式&#xff0c;它可以在一个文件中容纳无限数量的视频、音频、图片或字幕轨道&#xff0c;mp4格式也是被我们每个人所熟知&#xff0c;因为我们每个人几乎每天都会接触或者…

Spring入门教程

目录 一、Spring最基本的使用 1.创建Maven项目(不需要模板) 2.添加Spring框架支持 3.添加启动类(没啥可说的符合规范即可) 4.创建bean对象 5.将bean对象注册到Spring中 (a)先在resources文件夹中创建一个xml文件(注意:是test文件用了.xml后缀 不是直接创建一个xml文件) (…

[ChatGPT] 从 GPT-3.5 到 GPT-5 的进化之路 | ChatGPT和程序员 : 协作 or 取代

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601;…

FastDFS总结

目录 概述 什么是分布式文件系统 核心概念 目录结构 上传机制 下载机制 Linux中搭建FastDFS 常用指令 SpringBoot整合FastDFS FastDFS集成Nginx 概述 FastDFS是一个开源的轻量级分布式文件系统。它解决了大数据量存储和负载均衡等问题。特别适合以中小文件&#xff…

Android输入法不使用多客户端多屏适配-Android12

Android输入法不使用多客户端多屏适配-Android12 1、IME屏幕之间切换2、属性配置3、屏幕之间切换 IME 窗口 在非默认屏幕上运行的应用 1、IME屏幕之间切换 系统使用一个 IME&#xff0c;但可以在屏幕之间切换&#xff0c;以跟踪用户焦点。Android 10 默认所有第一方和第三方 IM…