当前位置:   article > 正文

【扫雷游戏】(代码通俗易懂+递归优化及实现)_扫雷小游戏代码优化

扫雷小游戏代码优化


前言

本系列博文仅为博主个人学习笔记,通过博客理清学习思路用于复习。如有记述不周到的地方请谅解;如能指出,更加感谢。


一、前期准备–游戏介绍

      扫雷游戏它是由row * col的格子拼起来,游戏规则:这款游戏的玩法是在一个99(初级),1616(中级),16*30(高级),或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个)。由玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束。
扫雷

// 本程序采用两个二维数组存储棋盘
	char mine[row][col] ; // 用来存储雷的信息
	char show[row][col] ; // 用来展示当前玩家展开棋盘的信息
```![扫雷](https://img-blog.csdnimg.cn/20210429214450977.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjQ5NzYw,size_16,color_FFFFFF,t_70)
## 1.该如何用c语言实现这样一款游戏 ---- 代码分析
    该游戏主要步骤就是两步1.如何设置雷2.如何排查雷。

1. 设置雷

```c
	//随机产生一对坐标,存储在x ,y当中
	int x = rand() % row + 1 ;
	int y = rand() % col + 1 ;
	//若存储地雷的二维数组该坐标不是雷,则将其设置成雷
	if(mine[x][y] == '0'){
		mine[x][y] = '1';
	}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2、排查雷
      玩家输入一对坐标,对坐标进行判断是否是合法输入,如果是合法输入,则继续判断该坐标对应的mine数组是否为雷,若为雷,则结束游戏,提示玩家您不小心踩到啦雷,游戏结束;若没有踩到雷,则继续游戏,并将该格子对应坐标周围所有的雷数展示出来,玩家继续挖雷,直到所有的不是雷的格子被玩家全部挖出,则游戏结束,提示玩家获胜。

playerMove(char mine[][COLS],char show[][COLS], int row, int col) {

 int x = 0;
 int y = 0;
 int count = 0;

 while (count < row * col - NUM_MINE) {
 	printf("请输入您要排除的雷的坐标:");
 	scanf("%d %d", &x, &y);
 	if (x >= 1 && x <= row && y >= 1 && y <= col) {
 		if (mine[x][y] == '1') {
 			printf("不好意思,你被炸啦,游戏结束\n");
 			break;
 		}
 	    /*int ret   = count_mine(mine, x, y);
 		show[x][y] = ret + '0';
 		count++;*/
 		else {
 		//对代码的递归优化,详细请见下文,功能是将与输入坐标周围8个格子所有不是雷的展开,提高用户游戏体验。
 			OpenMine(mine, show, row, col, x, y, &count);
 		//打印当前游戏棋盘的状态
 			Display(show, row, col);
 		}
 	}
 	else {
 		printf("输入坐标非法:\n");
 	}
 }
 if (count >= (col * row - NUM_MINE)) {
 	printf("恭喜您,扫雷成功\n");
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

二、代码的具体实现

本程序分为三个文件 game.h 头文件,game.c 具体实现文件,test.c测试文件 。

1. game.c 头文件

#include <stdio.h>

#define NUM_MINE 10
#define ROW 9
#define COL 9

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

//initial array 1. mine 2. show
initial(char board[][COLS], int rows, int col,char set);

//display 1. mine 2. show
Display(char board[][COLS], int row, int col);

//set mine
set_mine(char mine[][COLS], int row, int col);

//remove mine 
playerMove(char mine[][COLS],char show[][COLS], int row, int col);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2. game.c具体实现文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

//initial array 1. mine 2. show
initial(char board[][COLS], int rows, int cols,char set) {
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}

	}
}

//display 1. mine 2. show
Display(char board[][COLS], int row, int col) {
	printf("------扫雷游戏------\n");
	for (int i = 0; i <= row; i++) {
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("------扫雷游戏------\n");


}

//set mine
set_mine(char board[][COLS], int row, int col) {
	int count = NUM_MINE;

	while (count) {
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0') {
			board[x][y] = '1';
			count--;
		}
	}
}
//count mine by every grid
static int count_mine(char mine[][COLS], int x, int y) {
	return mine[x - 1][y - 1] +
		mine[x-1][y] +
		mine[x - 1][y + 1] +
		mine[x][y - 1] +
		mine[x][y + 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] - '0' * 8;
}

//open mines one by one
static void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y,int *level)
{
	(*level)++;
	if (mine[x][y] == '1' || x < 1  || x > row || y < 1 || y > col || show[x][y] != '*') {
		(*level)--;
		return;
	}
	int ret = count_mine(mine, x, y); //调用统计雷个数的函数。
	if (!ret)
	{
		show[x][y] = ' ';
		//要确定周围8个坐标本身不是雷,才递归它周围的。
		OpenMine(mine, show, row, col, x - 1, y - 1,level);
		OpenMine(mine, show, row, col, x, y - 1,level);
		OpenMine(mine, show, row, col, x + 1, y - 1, level);
		OpenMine(mine, show, row, col, x - 1, y, level);
		OpenMine(mine, show, row, col, x + 1, y, level);
		OpenMine(mine, show, row, col, x - 1, y + 1, level);
		OpenMine(mine, show, row, col, x, y + 1, level);
		OpenMine(mine, show, row, col, x + 1, y + 1, level);
	}
	else
	{
		show[x][y] = ret + '0'; //显示该坐标周围有几个雷
		return;
	}

	
}

//playermoving
playerMove(char mine[][COLS],char show[][COLS], int row, int col) {

	int x = 0;
	int y = 0;
	int count = 0;

	while (count < row * col - NUM_MINE) {
		printf("请输入您要排除的雷的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col) {
			if (mine[x][y] == '1') {
				printf("不好意思,你被炸啦,游戏结束\n");
				break;
			}
		    /*int ret   = count_mine(mine, x, y);
			show[x][y] = ret + '0';
			count++;*/
			else {
				OpenMine(mine, show, row, col, x, y, &count);
				Display(show, row, col);
			}
			
		}
		else {
			printf("输入坐标非法:\n");
		}
	}

	if (count >= (col * row - NUM_MINE)) {
		printf("恭喜您,扫雷成功\n");
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126

3. test.c 测试文件

#include "game.h"
#include <stdlib.h>
#include <time.h>
void menu() {
	printf("*********************\n");
	printf("******1. play   *****\n");
	printf("******0. exit   *****\n");
	printf("*********************\n");
}
void game() {
	//定义两数组来存储数据
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

	//initial array
	initial(mine, ROWS, COLS,'0');
	initial(show, ROWS, COLS,'*');
	//Display(mine, ROW, COL);
	Display(show, ROW, COL);

	//set mine 
	set_mine(mine, ROW, COL);
	playerMove(mine,show, ROW, COL);
	Display(mine, ROW, COL);


}
int main() {

	srand((unsigned)time(NULL));
	int input = 0;
	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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

      此处重点来说说openmine 这个函数,功能是一个一个的展开周围的8个格子,若该格子的坐标不合法,曾访问过或者是雷,则满足条件,return返回,若满足以上条件均不满足,则将该格子周围的雷数进行统计,若统计数不为零,则不将其周围格子进行展开,只将其格子周围的雷数展示出来;若统计数为0,则将该格子置为‘   ’,并进入下一个格子 的判断:将该格子的左上,左,左下,正上,正下,右上,右,右下8个格子继续进行以上三个判断,并用一个变量count计数,依次判断,直到所有相邻的格子判断完毕。若count < row * col - 雷数, 则玩家继续输入坐标进行下一轮判断。重复上述动作,在玩家没有踩到雷的情况下正常,直到 count < row* col - 雷数不满足条件,跳出循环 ,提示玩家胜利。

                                            游戏界面展示
在这里插入图片描述

总结:

      扫雷游戏还是比较简单的,希望同学们一起努力,从c语言青铜慢慢变成c语言王者,我们一起在山顶相遇。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号