如何用C语言快速实现初级版扫雷(步骤详细)

2022-11-30 08:04:33 浏览数 (1)

目录

前言

问题描述

工具

基本思路和流程

扫雷的规则

代码实现思路

实现步骤

模块化

菜单界面

 代码

选择的实现

初始化和打印雷区

考虑问题

雷区

使用宏定义

初始化

棋盘

设置雷

打印

考虑如何实现图表

参考代码

效果图

玩家排雷

考虑问题

免雷

査雷

周围雷数

雷区展开

胜利判断

显示用时


前言


https://www.saolei123.com/

附上扫雷小游戏链接,先来体味感受下真正的扫雷是怎样的

本文章为手把手讲解实现C语言扫雷(好好看,相信不会太难的说) 当你自己完成后一定成就感幸福感满满的!!

问题描述


用C语言实现小游戏扫雷初级版(9x9棋盘/10个地雷)

工具

vs2019

基本思路和流程


扫雷的规则

尽快找出雷区中的所有不是地雷的方块 根据点击格子出现的数字找出所有非雷格子 同时避免踩雷,踩到一个雷即全盘皆输

代码实现思路

1.菜单选择开始或者退出游戏 2.初始化并打印雷区 3.第一次免雷和周边雷排查 4.雷区展开 5.判断胜利 6.游戏结束后展示玩家用时

实现步骤


模块化

1.test.c :写整个游戏实现思路流程 2.game.c: 写游戏实现思路中的各个函数的定义,完成函数内容实现函数功用 3.game.h :引用需要用到的头文件,以及对各个自定义函数的声明 (其他模板上方只需要加上 #include “game.h”,避免重复引用相同头文件) 注:模块化便于管理和修改

菜单界面

比较简单直接上代码

 代码

代码语言:javascript复制
//菜单界面
void menu()
{
	printf("************************n");
	printf("*******  1.play  *******n");
	printf("*******  0.exit  *******n");
	printf("************************n");
}

选择的实现

玩家通过输入1/0 来选择是开始游戏还是退出游戏 用do while语句实现比较适合

代码语言:javascript复制
do
	{
		menu();
		printf("请输入选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			printf("成功退出游戏!n");
			break;
		case 1:
			printf("欢迎进入游戏!n");
			game();
			break;
		default:
			printf("输入出错,请重新输入n");
			break;
		}
	} while (input);

初始化和打印雷区


考虑问题

因为我们在设计算法时需要统计坐标周围8个方位雷的个数 假如要统计边界坐标周围雷的个数,那么就会有数组越界的问题 那我们就要在9X9的边界多上一圈元素,也就要定义11X11的数组元素 这些元素我们显示给玩家看就可以了

雷区

使用9行9列的二维数组来表示,元素类型是char

代码语言:javascript复制
	char mine[ROWS][COLS] = { 0 };//存放雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息

使用宏定义

1.推高代码可读性,后续代码中遇到,方便理解含义 2.提高扩展性,如果将来要修改棋盘尺寸,代码修改会很方便

代码语言:javascript复制
#define ROW 9
#define COL 9//显示规格

#define ROWS ROW 2
#define COLS COL 2//实际规格

#define EASY_COUNT 10//布置雷个数

初始化

棋盘

代码语言:javascript复制
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows,int cols)
{
	int i = 0;
	for (i = 0; i < rows; i  )//行
	{
		int j = 0;
		for (j = 0; j < cols; j  )//列
		{
			board[i][j] = '0';
		}
	}
}

设置雷

代码语言:javascript复制
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = COUNT;
	while (count)
	{
		//生成随机下标
		int x = rand() % row   1;//取余后的范围是0-8
		int y = rand() % col   1;//加一后符合游戏范围
		if (board[x][y] != '1')
		{
			board[x][y] = '1';
			count--;//设置10个后 count为0 不再循环
		}
	}
}

打印


考虑如何实现图表

什么时候该打印 什么时候不该打印 打印的间距 换行的考虑 打印布局的美观性

参考代码

代码语言:javascript复制
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;//在外围打印标数以便于玩家定位坐标
	printf("-----------------------------------------n");
	for (i = 0; i <= 9; i  )//0-9打印最上排数字
	{
		printf("| %d ", i);
	}
	printf("|n");
	printf("-----------------------------------------n");
	for (i = 1; i <= row; i  )
	{
		int j = 0;
		printf("| %d |", i);//1-9打印最左排数字
		for (j = 1; j <= col; j  )
		{
			printf(" %c |", board[i][j]);
		}
		printf("n");//一定注意要换行
		printf("-----------------------------------------n");//每打印一排内容,再打印一排横线,形成表格,提升美观
	}

效果图

 玩家排雷


考虑问题

1.因为实际雷区是11x11的,也就是说显示雷区的下标是从1开始的,符合玩家思维 2.排雷范围 3.第一次免雷 4.显示周围雷数

免雷

代码语言:javascript复制
//第一次免雷
void FirstSafe(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
	int count = 0;
	if (mine[x][y] == '1')
	{
		mine[x][y] = '0';//替换
		while (1)
		{
			int rx = rand() % row   1;
			int ry = rand() % col   1;
			if (mine[rx][ry] == '0' && (rx != x) && (ry != y))
			{
				mine[rx][ry] = '1';//再次布雷
				break;
			}
		}
		count = GetMineCount(mine, x, y);
		show[x][y] = count   '0';
		ExtendNotMine(mine, show, x, y, '0', '*');
		DisplayShow(show, row, col);
	}
}

査雷

代码语言:javascript复制
void FindMine(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)//排查范围
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);
				show[x][y] = count   '0';//替换成字符数,显示雷数
				DisplayBoard(show, ROW, COL);
			}
		}
		else
		{
			printf("坐标非法,重新输入n");
		}
	}

周围雷数

代码语言:javascript复制
int GetMineCount(char mine[ROWS][COLS], int x, int y)//获取周边一圈雷个数的信息
{
	int ret = 0;
	for (int i = x - 1; i <= x   1; i  )
	{
		for (int j = y - 1; j <= y   1; y  )//3X3范围
		{
			ret  = mine[i][j];
		}
	}
	return ret - mine[x][y] - 8 * '0';//注:'1'-'0'=1(ASCII码值)
}//返回值代表雷的个数

雷区展开


考虑用递归实现

代码语言:javascript复制
//扩展排雷,展开周围非雷区
void ExtendNotMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int n = 0;
	n = GetMineCount(mine, x, y);
	if (n == 0)
	{
		show[x][y] = ' ';//如果周围没有雷,将中心赋值为空格
		int i = 0;
		int j = 0;
		for (i = x - 1; i <= x   1; i  )
		{
			for (j = y - 1; j <= y   1; j  )
			{
				if (mine[i][j] =='0'&& show[i][j]=='*')//周围坐标满足自身不是雷且还是初始化字符,进入递归再次扩展排雷
				{
				{
					ExtendNotMine(mine, show, i, j, '0', '*');//递归排雷
				}
			}
		}
	}
	else
		show[x][y] = n   '0';//如果附近有雷,展示雷的个数
}

胜利判断


遍历雷区剩余的初始值个数进行判断

代码语言:javascript复制
//求展示扫雷棋盘上含有初始化字符的个数,用来判断游戏何时终止
int AroundInitCount(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = 1; i <= row; i  )
	{
		for (j = 1; j <= col; j  )
		{
			if (board[i][j] == '0')
				count  ;
		}
	}
	return count;
}
代码语言:javascript复制
if (count == EASY_COUNT)
				{
					printf("恭喜你!扫雷成功!n");
					DisplayShow(mine, ROW, COL);
					break;
				}

显示用时


代码语言:javascript复制
void SpendTime(clock_t start)
{
	clock_t end = clock();
	clock_t total = end - start;
	printf("游戏所用时间为:%.1lf秒!n", 1.0 * total / CLOCKS_PER_SEC);
}

0 人点赞