C语言 —— 扫雷小游戏详解附源码

2 篇文章 0 订阅
1 篇文章 0 订阅

目录

 一.是否进入游戏的判断

二.游戏主体实现

(一).创建棋盘

(二).初始化棋盘

(三).棋盘打印函数

(四).布置雷

(五).玩家排雷

(六).判断游戏状态(输赢等)

 三.最后效果图和原码赠送


 这种类型的小游戏,是对基础知识很好的复习!

实现前准备:

        一 . 了解游戏如何玩

简单版举例:

        一个9*9的棋盘中有10个雷,你要将他们一一排除,直到排除完所有雷,踩到雷你就会死亡。

踩到不是雷的地方,会扫描附近8格方格,并会告诉你这附近8个方格中的雷数。

如:

图中的2附近8个方格中,只有最后两个未排除那他们一定就是雷

 你不信?你踩下去试试:

二.实现前思想

  1. 可以用二维数组来当棋盘
  2. 用1当雷0为非雷,这样可以方便计算附近的雷数
  3. 编写函数,实现输入输出和判断游戏状态的函数

三. 解决代码较多问题

        因为考虑到代码量较多,为了代码的整洁性,可读性,我把代码分成了3个部分

  •         minesweeper.c    ——    用来实现游戏的本身的逻辑
  •         game.c   ——    功能函数的实现
  •         game.h   ——    函数的声明和头文件和宏的等声明

 一.是否进入游戏的判断

不管如何要先进入系统,所有用do while循环实现,然后打印一个菜单给玩家选择:

菜单:

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

}

 有了菜单玩家要选择,创建input变量,把退出项设为0,input就可以作为循环的表达式,在c语言中0为假1为真,真执行,假不执行,玩家选择0为假喜欢停止退出程序

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");
		}
	} while (input);
	return 0;
}

二.游戏主体实现

        游戏主体需要实现各种功能,把他们放在game.c文件中,函数、宏、头文件、声明在game.h头文件中

(一).创建棋盘

考虑到如果是边缘的方块要检测,那就非常的不好办了:

 我们干脆做大一圈,但只使用内圈,这样排除起来就方便了:

 定义宏做为二维数组参数:


//控制棋盘大小:
//如:9*9
#define ROW 9
#define COL 9

//实际使用+2保证棋盘大一圈
#define ROWS ROW+2
#define COLS COL+2

创建二维数组,用来做棋盘,由于考虑到1作为了雷,那检测显示附近的雷数如果是1就麻烦了,所以创建两个数组一个用来放雷,一个用来打印和显示附近雷数。

//设计两个数组存放信息
	//mine放雷
	//show用来打印和附近雷的数量
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

(二).初始化棋盘

我们把mine放雷:1为雷0为非雷

再把show用来打印和附近的雷数:#为雷*为非雷

实参:

	//mine - 全部初始化为 0 
	//show - 全部初始化为 *
	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');

 形参:

//初始化
void init_board(char board[ROWS][COLS], char 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;//set为传过来的图案如:0或*
		}
	}
}

 函数声明放在game.h文件中:

后面就不说函数定义了都跟函数形参那一排一样

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

(三).棋盘打印函数

初始化好了棋盘,我们需要一个能够随时打印棋盘的函数:

实参:

display_board(show, ROW, COL);

形参:

//棋盘打印
void display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= row; 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");
	}
	
}

效果:

 其余部分计是棋盘

(四).布置雷

棋盘出来了但里面还没有雷

这里就要介绍前面主函数中的:

	srand((unsigned int)time(NULL));

了解:

#include <stdlib.h>

1.rand库函数 生成一个随机数 在调用rend之前,需要先调用srand随机生成器

2.srand 设置一个随机的起点

//(强制类型转换unsigned int)是因为srand里的数据类型是unsigned int
//NULL是因为time是返回当前时间(秒数),这里并不需要他返回
srand((unsigned int)time(NULL));

 这里我们再定义一个宏可以随意的控制雷的数量:

//控制雷数:
#define EASY_COUNT 10

 函数实现:

//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		//EASY_COUNT = 10
		//随机值 % 9 = 0 - 8的数字 
		//+ 1 产生 1 - 9 的数
        //刚好符合我们要使用的二维数组的下标
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

效果:

(五).玩家排雷

由于我们存放的是字符数字 如: ' 3 '

他的ASCII码并不是3看图:

 但是可以发现这样的规律:

0 - 9字符的ASCII码减去0得原数字

' 2 ' - ' 0 ' = 50 - 48 = 2

那我们就可以把周围排查的数加起来的和,减去 8(排查的范围) * 字符 ' 0 '  = 周围的雷数

这样就有了排查雷的函数:


//排查周围的雷
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');
}

提醒

  • mine数组是放雷的
  • show是用来显示的
//玩家排除雷,初步
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (1)
	{
		printf("请输入排雷坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			int count = get_mine_count(mine, x, y);//设计一个函数来排查周围8个方格中的雷
			show[x][y] = count + '0';
			display_board(show, ROW, COL);
		}
		else
		{
			printf("非法坐标,请重新输入\n");
		}
	}
}

效果: 

 可以看到,排查的位置周围有两个雷

(六).判断游戏状态(输赢等)

 

在这段代码中我们只判断了,输入的值超出界限的情况,但是还有许多游戏状态:

  • 还有坐标重复
  • 被雷炸死
  • 还有最后胜利的状态

加入判断:

//排雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	// win依依排查到最后等于71不在 < 9 * 9 - 10 = 71
	while (win < row * col - EASY_COUNT)//当win排查出所有雷,停止循环
	{
		printf("请输入排雷坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("非常遗憾你被炸死了\n");
					display_board(mine, ROW, COL);
					break;
				}
				else
				{
                    //设计一个函数来排查周围8个方格中的雷
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';//得出来的值+‘ 0 ’,就得数字字符
					display_board(show, ROW, COL);//打印出来看
					win++;//记录排查正确的数量
				}
			}
			else
			{
				printf("请重新输入,该坐标已输入\n");
			}
			
		}
		else
		{
			printf("非法坐标,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你排除了所有雷\n");
		display_board(mine, ROW, COL);
	}
}

 三.最后效果图和原码赠送

        这里为了给大家展示我把雷的数量改到79,把mine放雷的棋盘一起打印出来,给大家看游戏各个状态

 

 胜利状态:

重复输入状态:

超出范围状态:

 炸死状态:

 源码:

minesweeper.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()
{
	//设计两个数组存放信息
	//mine放雷
	//show用来打印和附近雷的数量
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };


	//mine - 全部初始化为 0 
	//show - 全部初始化为 *
	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');

	//打印棋盘
	/*display_board(mine, ROW, COL);
	display_board(show, ROW, COL);*/

	//布置雷
	set_mine(mine, ROW, COL);
	/*display_board(mine, ROW, COL);*/
	display_board(show, ROW, COL);

	//排雷和游戏状态的判断
	find_mine(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");
		}
	} while (input);
	return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化
void init_board(char board[ROWS][COLS], char 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;//set为传过来的图案如:0或*
		}
	}
}

//棋盘打印
void display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= row; 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");
	}

}

//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		//EASY_COUNT = 10
		//随机值 % 9 = 0 - 8的数字 
		//+ 1 产生 1 - 9 的数
		//刚好符合我们要使用的二维数组的下标
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

//排查周围的雷
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 find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	// win依依排查到最后等于71不在 < 9 * 9 - 10 = 71
	while (win < row * col - EASY_COUNT)//当win排查出所有雷,停止循环
	{
		printf("请输入排雷坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("非常遗憾你被炸死了\n");
					display_board(mine, ROW, COL);
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);//设计一个函数来排查周围8个方格中的雷
					show[x][y] = count + '0';//得出来的值+‘ 0 ’,就得数字字符
					display_board(show, ROW, COL);//打印出来看
					win++;
				}
			}
			else
			{
				printf("请重新输入,该坐标已输入\n");
			}
			
		}
		else
		{
			printf("非法坐标,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你排除了所有雷\n");
		display_board(mine, ROW, COL);
	}
}

玩家排除雷,初步
//void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
//{
//	int x = 0;
//	int y = 0;
//	int win = 0;
//	while (1)
//	{
//		printf("请输入排雷坐标:>");
//		scanf("%d %d", &x, &y);
//		if (x >= 1 && x <= row && y >= 1 && y <= col)
//		{
//			int count = get_mine_count(mine, x, y);//设计一个函数来排查周围8个方格中的雷
//			show[x][y] = count + '0';
//			display_board(show, ROW, COL);
//		}
//		else
//		{
//			printf("非法坐标,请重新输入\n");
//		}
//	}
//}

game.h

//控制棋盘大小:
//如:9*9
#define ROW 9
#define COL 9


//实际使用+2保证棋盘大一圈
#define ROWS ROW+2
#define COLS COL+2


//控制雷数:
#define EASY_COUNT 10


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


//初始化棋盘
void init_board(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void display_board(char board[ROWS][COLS], int row, int col);
//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col);
//排雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

如果这篇博客对你有帮助,一键三连走一波,你们的支持是我最大的动力!!!

  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值