C语言实现简易版 扫雷 步骤及代码

一、基本思路

首先创建二维数组,来表示地图

每一个格子要表示的信息

  1. 未翻开状态(草地)和已翻开状态(数字)

  2. 该格子是地雷或者不是地雷(1表示是地雷,0表示不是地雷)

使用两个二维数组来表示以上两组状态:

第一组二维数组
char showMap[9][9];表示每个格子的翻开和未翻开状态
*表示未翻开,字符‘0’-‘8’表示已翻开的数字

第二个二维数组:
char mineMap[9][9];表示每个格子是否是地雷
‘1’表示是地雷,‘0’表示不是地雷

二、基本流程

1.创建地图并初始化

使用宏定义的原因:

  1. 提高代码的可读性
  2. 提高扩展性,便于后续修改
#define MAX_ROW 9
#define MAX_COL 9
#define MINE_COUNT 10

初始化:

  1. showMap初始化由*构成表示未翻开
  2. mineMap由0、1组成( ‘1’表示是地雷,‘0’表示不是地雷),一开始都为0,随后由电脑随机在地图上生成1
void init(char showMap[MAX_ROW][MAX_COL], char mineMap[MAX_ROW][MAX_COL]) {
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			showMap[row][col] = '*';
			mineMap[row][col] = '0';
		}
	}
	srand((unsigned int)time(0));
	int mineCount = 0;
	while (mineCount < MINE_COUNT ){
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;
		if (mineMap[row][col] == '1') {
			continue;
		}
		mineMap[row][col] = '1';
		mineCount++;
	}
}

使用两重循环就可初始化,这里可使用 memset 更为方便

memset功能 :把一段内存上的每个字节都设置成一个具体的值

    memset(showMap, '*',MAX_ROW * MAX_COL);
	memset(mineMap,  '0', MAX_ROW * MAX_COL);
	代替两重循环

2.打印地图showMap

打印出地图

void print(char theMap[MAX_ROW][MAX_COL]) {
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			printf("%c ", theMap[row][col]);
		}
		printf("\n");
	}
} 

3.让玩家输入坐标,表示要翻开的位置

int row = 0;
		int col = 0;
		printf("请输入坐标(row,col):");
		scanf("%d %d", &row, &col);
		//进行合法性判定
		if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL){
			printf("你的输入有误,请重新输入!\n");
			continue;
		}
		if (showMap[row][col] != '*'){
			printf("你的输入的位置已经翻开,请重新输入!\n");
			continue;
		}

4.判定是否踩雷

如果翻开的位置为1,则踩到地雷,游戏结束

if (mineMap[row][col] == '1') {
			printf("您踩雷了!!结束游戏\n");
			break;
		}

5.更新showMap,在翻开位置显示周围有多少个地雷

void update(char showMap[MAX_ROW][MAX_COL], 
	char mineMap[MAX_ROW][MAX_COL],int row ,int col) {
	 //表示周围的地雷个数
	  int count = 0;
	  for (int r = row - 1; r <= row + 1; r++) {
		  for (int c = col - 1; c <= col + 1; c++) {
			  if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
				  //此时r c坐标超出棋盘范围,直接跳出
				  continue;
			  }
			  if (r == row && c == col) {
				  continue;
			  }
			  if (mineMap[r][c] == '1') {
				  count++;
			  } 
		  }
	  }
	   showMap[row][col] = '0'+ count;
	}

6.判定玩家是否翻开了所有位置 若没有返回步骤2

定义openedCount,表示翻开的不是地雷的土地数,每次更新地图后openedCount + 1

openedCount++;
		if (openedCount == MAX_ROW * MAX_COL - MINE_COUNT) {
			printf("恭喜你获胜了!\n");
			break;
		}

三、代码实现

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#define MAX_ROW 9
#define MAX_COL 9
#define MINE_COUNT 10

void init(char showMap[MAX_ROW][MAX_COL], char mineMap[MAX_ROW][MAX_COL]) {
	memset(showMap, '*',MAX_ROW * MAX_COL);
	memset(mineMap,  '0', MAX_ROW * MAX_COL);
	srand((unsigned int)time(0));
	//随机产生十个位置作为地雷
	int mineCount = 0;
	while (mineCount < MINE_COUNT ){
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;
		if (mineMap[row][col] == '1') {
			continue;
		}
		mineMap[row][col] = '1';
		mineCount++;
	}
}

//形参名字叫做'map'不合适. C++标准库里有一个std::map

void print(char theMap[MAX_ROW][MAX_COL]) {
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			printf("%c ", theMap[row][col]);
		}
		printf("\n");
	}
} 


void update(char showMap[MAX_ROW][MAX_COL], 
	char mineMap[MAX_ROW][MAX_COL],int row ,int col) {
	 //表示周围的地雷个数
	  int count = 0;
	  for (int r = row - 1; r <= row + 1; r++) {
		  for (int c = col - 1; c <= col + 1; c++) {
			  if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
				  //此时r c坐标超出棋盘范围,直接跳出
				  continue;
			  }
			  if (r == row && c == col) {
				  continue;
			  }
			  if (mineMap[r][c] == '1') {
				  count++;
			  } 
		  }
	  }

	  //如果直接赋值 showMap 是char count是int  
	  //假设count是2,当前row col位置的元素就被设置成了ASCII值为2的字符,而不是‘2’
	  // 类似于这样的转换,只是C语言中是这么写的,其他语言一般不允许 字符类型 和 整数类型 进行混合运算
	  showMap[row][col] = '0'+ count;
	}
int main(){
		//创建地图并初始化
	char showMap[MAX_ROW][MAX_COL] = { 0 };
	char mineMap[MAX_ROW][MAX_COL] = { 0 };
	init(showMap, mineMap);
	int openedCount = 0;
	while (1) {
		//加上清屏
		system("cls");
		//2.打印地图
		print(showMap);
		//TODU此处为了验证update函数的正确性
		/* 先把地雷的布局打印出来
	   printf("=====================\n");
	   print(mineMap);*/
		//3.玩家输入坐标
		int row = 0;
		int col = 0;
		printf("请输入坐标(row,col):");
		scanf("%d %d", &row, &col);
		//进行合法性判定
		if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL){
			printf("你的输入有误,请重新输入!\n");
			continue;
		}
		if (showMap[row][col] != '*'){
			printf("你的输入的位置已经翻开,请重新输入!\n");
			continue;
		}
		//4.判断是否踩雷
		if (mineMap[row][col] == '1') {
			printf("您踩雷了!!结束游戏\n");
			break;
		}
		//5.更新showMap,显示当前位置周围有多少个雷
		update(showMap, mineMap, row, col);
		//6.进行游戏胜利的判定,统计当前格子数量
		openedCount++;
		if (openedCount == MAX_ROW * MAX_COL - MINE_COUNT) {
			printf("恭喜你获胜了!\n");
			break;
		}
		
	}
	return 0;
}



四、结果演示

此处为了验证update函数的正确性,可将地雷的布局打印出来,如下展示
在这里插入图片描述

在这里插入图片描述

以上为本次博客全部内容~~ 欢迎批评指正

  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值