C语言实战项目【二】经典小游戏【扫雷】

举报
xcc-2022 发表于 2022/05/23 09:33:51 2022/05/23
【摘要】 此为第一个纯C制作项目游戏,内容富含指针,数组 循环。


目录


扫雷游戏效果对比总览

实现的操作:

玩家须知:

游戏准备

1.棋盘格式

2.初始化棋盘

3.打印棋盘

4.随机布置雷(会用rand生成随机)

6.排查雷

7.统计雷数量

完整代码



扫雷游戏效果对比总览

编辑编辑












实现的操作:

  1. 显示周围的雷数量
  2. 随机布雷
  3. 第一次下子,不炸死
  4. 坐标周围没雷,可以实现展开
  5. 游戏结束后展示给玩家

玩家须知:

  1. 数字n代表有n个雷
  2. 雷的总数量设置为10

编辑

游戏准备

我们使用坐标的方式进行排雷,一次坐标查看一个格子,总共有81个格子,分别为9行9列;9行9列?听着好耳熟,对啦,就是我们学过的二维数组;既然是数组,那坐标(0,0)不就是第一行的第一列吗?真聪明!不过这是聪明的程序员使用的方式,而外行认为第一行第一列那就是(1,1)呀;所以,我们在打印棋盘的时候要多打两行;不应该存储[9][9],因为我们排查雷都以9*9的格式,而如果在四个角落的话,就会受限,会越界;那时就要设置四个角落排查信息为3格子,比较麻烦。
    为防止访问越界,所以我们给他扩充两行两列,一律9*9排查,所以得11*11格式(辅助作用)

1.棋盘格式

这里解释为什么定义ROWS,COLS,ROW,COL这四个宏。

mine数组中,除了雷是用1表示,其他的元素都是用0表示,计算雷数时,把周围八个元素的值相加,得到的数刚好就是雷数。但是我们对边界上的元素进行排雷时,会出先数组的越界访问,产生意想不到的结果,这当然不是我们想要的。所以,对数组增加两行与两列(假设二维数组是9 * 9的,增加后变为11 * 11),对11 * 11的数组初始化,但我们使用的是9 * 9 的数组,在计算雷数时就不会出现错误了

#define EASY_COUNT 10//雷的总数量
#define ROW 9	//行
#define COL 9	//列

//为使用方便,这里区分格式的使用,本质还是9*9

#define ROWS ROW+2
#define COLS COL+2
char mine[ROWS][COLS]={0};//存放布置好的雷的信息
char show[ROWS][COLS]={0};//存放排查除的雷的信息

2.初始化棋盘

我们打印设计者棋盘要用数组real_mine,打印玩家棋盘要用数组show_mine,两个数组在开始必须要初始化,在设计者棋盘中字符0代表不是雷,字符1代表雷,先初始化两个数组
代码如下

	//初始化棋盘
	InitBoard(mine,ROWS,COLS,'0');//‘0’
	InitBoard(show,ROWS,COLS,'*');//‘*’
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set)
{

	int i = 0;
	int j = 0;
	for(i=0;i<rows;i++)
	
	{
		for(j=0;j<cols;j++)
		{
		
			board[i][j]=set;
		}
	}
}

3.打印棋盘


DisplayBoard(show,ROW,COL);//打印棋盘
//打印棋盘
void DisplayBoard(char board[ROWS][COLS],int row,int col )
{
	int i = 0;
	int j = 0;
	printf("-------------扫雷游戏----------------\n");
	//打印列号
	for(i=0;i<=col;i++)
	{
	
		printf("%d ",i);
	}
	printf("\n");
	for(i=1;i<=row;i++)
	{
	
		printf("%d ",i);
		for(j=1;j<=col;j++)
		{
		
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}
	printf("-------------扫雷游戏----------------\n");
}

4.随机布置雷(会用rand生成随机)

//布置雷
	SetMine(mine,ROW,COL);


void SetMine(char mine[ROWS][COLS],int row,int col)
{

	//布置雷
	int count = 10;
	while(count)
	{
		//生产随机的下标
		
		int x = rand()%row+1;
		int y= rand()%col+1;
		
		if(mine[x][y]=='0')
		{
		
			mine[x][y]='1';
			count--;
		}
	
		
	}
}

6.排查雷

接着就到了玩家进行排雷了,通过玩家输入坐标,程序把对应的数组元素赋值成周围一圈的雷数,要是踩到雷了,提示玩家玩得太菜 游戏结束。但这又有一个细节,我们创建的数组是字符数组,放置的是字符,把字符相加得到的是对应的ASCII码值。所以我们把相加后的值减去八个字符0的ASCII码值,得到的就是雷数了。我写了一个get_mine_num函数来计算雷数。

//排查雷
	FindMine(mine,show,ROW,COL);
//排查雷
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col)
{
	//1.输入排查坐标
	//2.检查坐标是不是雷
		//(1)是雷  - 很遗憾炸死了,游戏结束
		// (2)不是雷  - 统计坐标周围有几个雷 - 存储排查雷的信息到show数组,游戏继续

	int x = 0;
	int y = 0;
	int win = 0;
	while(win<row*col-EASY_COUNT)
	{
	
		printf("请输入要排查的坐标:>");
		scanf("%d %d",&x,&y);//x-(1-9),y-(1-9)

		//判断坐标合法性
		if(x>=1&&x<=row&&y>=1&&y<=col)
		{
			if(mine[x][y]=='1')
			{
				printf("很遗憾 ,你被炸死了\n");
				DisplayBoard(mine,row,col);
				break;
			}
			else
			{
			
				//不是雷的话,统计x,y坐标周围有几个雷
				int  count = get_mine_count(mine,x,y);
				show[x][y]=count+'0';
				//显示排查出的信息
				DisplayBoard(show,row,col);
				win++;
			}

		}
		else
			printf("坐标不合法,请重新输入!");

	}
	if(win==row*col-EASY_COUNT)
	{
	
		printf("排雷成功!\n");
		DisplayBoard(show,row,col);
	}
}

7.统计雷数量

编辑


//统计雷
static int get_mine_count(char mine[ROWS][COLS],int x,int y)
{
	return  mine[x-1][y]+
		mine[x-1][y-1]+
		mine[x][y-1]+
		mine[x+1][y-1]+
		mine[x+1][y]+
		mine[x+1][y+1]+
		mine[x][y+1]+
		mine[x-1][y+1]-8*'0';
}
至此所有的代码我们就完成了,接着是所有文件代码的整体展示

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define EASY_COUNT 10//雷的总数量
#define ROW 9	//行
#define COL 9	//列

//为使用方便,这里区分格式的使用,本质还是9*9

#define ROWS ROW+2
#define COLS COL+2

//初始化棋盘
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);

//打印棋盘
void DisplayBoard(char board[ROWS][COLS],int row,int col );

//布置雷
void SetMine(char mine[ROWS][COLS],int row,int col);

//排查雷
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);

void menu()
{

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

void game()
{
	/*不应该存储[9][9],因为我们排查雷都以9*9的格式,而如果在四个角落的话,
	就会受限,会越界;那时就要设置四个角落排查信息为3格子,比较麻烦。
	为防止访问越界,所以我们给他扩充两行两列,一律9*9排查,所以得11*11格式(辅助作用)*/

	char mine[ROWS][COLS]={0};//存放布置好的雷的信息
	char show[ROWS][COLS]={0};//存放排查除的雷的信息
	//初始化棋盘
	InitBoard(mine,ROWS,COLS,'0');//‘0’
	InitBoard(show,ROWS,COLS,'*');//‘*’

	//打印棋盘
	
	DisplayBoard(show,ROW,COL);

	//布置雷
	SetMine(mine,ROW,COL);
	//DisplayBoard(mine,ROW,COL);

	//排查雷
	FindMine(mine,show,ROW,COL);

}

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

void InitBoard(char board[ROWS][COLS],int rows,int cols,char set)
{

	int i = 0;
	int j = 0;
	for(i=0;i<rows;i++)
	
	{
		for(j=0;j<cols;j++)
		{
		
			board[i][j]=set;
		}
	}
}

//打印棋盘
void DisplayBoard(char board[ROWS][COLS],int row,int col )
{
	int i = 0;
	int j = 0;
	printf("-------------扫雷游戏----------------\n");
	//打印列号
	for(i=0;i<=col;i++)
	{
	
		printf("%d ",i);
	}
	printf("\n");
	for(i=1;i<=row;i++)
	{
	
		printf("%d ",i);
		for(j=1;j<=col;j++)
		{
		
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}
	printf("-------------扫雷游戏----------------\n");
}

void SetMine(char mine[ROWS][COLS],int row,int col)
{

	//布置雷
	int count = 10;
	while(count)
	{
		//生产随机的下标
		
		int x = rand()%row+1;
		int y= rand()%col+1;
		
		if(mine[x][y]=='0')
		{
		
			mine[x][y]='1';
			count--;
		}
	
		
	}
}
//统计雷
static int get_mine_count(char mine[ROWS][COLS],int x,int y)
{
	return  mine[x-1][y]+
		mine[x-1][y-1]+
		mine[x][y-1]+
		mine[x+1][y-1]+
		mine[x+1][y]+
		mine[x+1][y+1]+
		mine[x][y+1]+
		mine[x-1][y+1]-8*'0';
}

//排查雷
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col)
{
	//1.输入排查坐标
	//2.检查坐标是不是雷
		//(1)是雷  - 很遗憾炸死了,游戏结束
		// (2)不是雷  - 统计坐标周围有几个雷 - 存储排查雷的信息到show数组,游戏继续

	int x = 0;
	int y = 0;
	int win = 0;
	while(win<row*col-EASY_COUNT)
	{
	
		printf("请输入要排查的坐标:>");
		scanf("%d %d",&x,&y);//x-(1-9),y-(1-9)

		//判断坐标合法性
		if(x>=1&&x<=row&&y>=1&&y<=col)
		{
			if(mine[x][y]=='1')
			{
				printf("很遗憾 ,你被炸死了\n");
				DisplayBoard(mine,row,col);
				break;
			}
			else
			{
			
				//不是雷的话,统计x,y坐标周围有几个雷
				int  count = get_mine_count(mine,x,y);
				show[x][y]=count+'0';
				//显示排查出的信息
				DisplayBoard(show,row,col);
				win++;
			}

		}
		else
			printf("坐标不合法,请重新输入!");

	}
	if(win==row*col-EASY_COUNT)
	{
	
		printf("排雷成功!\n");
		DisplayBoard(show,row,col);
	}
}


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。