【C】扫雷游戏的初步实现与详细解析

扫雷游戏

学完了数组与函数,实现一个简单的扫雷游戏

扫雷游戏的功能说明

  • 使用控制台实现经典的扫雷游戏
  • 游戏可以通过菜单实现继续玩或者退出游戏
  • 扫雷的棋盘是9*9的格子
  • 默认随机布置10个雷
  • 可以排查雷
    如果位置不是雷,就显示周围有几个雷
    如果位置是雷,就炸死游戏结束
    把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

思路:

test.c ---- 游戏的测试逻辑

game.c -----函数的实现

game.h ------函数的声明

菜单的实现

输入1----玩游戏

输入0---退出游戏

如果想要一直玩,需要用到while来进行循环

布置棋盘:

9*9的数组来存放数据-----布置好雷的信息

如何区别是雷和不是雷:布置雷的地方存1,没有雷的地方存0

但是此时,排查一个坐标的时候,假如这个坐标周围含有一个雷,显示的1表示该范围内雷的个数,与上面布置雷的1产生歧义,故可以再创建一个大小相同的数组,将排查雷的信息放入该数组(没有排查任何坐标的时候,这个数组显示*)

在排查边缘的坐标时,排查的范围超出棋盘的范围,如果依次进行判断就会非常麻烦,故可以创建11*11的字符数组

布置雷

随即设置需要用到srand和rand函数,详细请看往期"猜数字游戏"

%row是为了适应棋盘的大小,当row=0时,因为余数不能大于除数,rand()%row的范围在0~8,此时想要得到0 ~9范围内的随机数字,+1即可

c 复制代码
int x = rand()%row+1;//返回值1~9
int y = rand()%col+1;//返回值1~9

排查雷

  • 要保证输入正确:if (x >= 1 && x <= row && y >= 1 && y <= col)
  • 输入正确之后,验证该位置是否被排查过if (show[x][y] == '*')
  • 没被排查过,判断是否为雷if (mine[x][y] == '1')
  • 是雷则结束游戏,不是雷计算周围雷个数(将周围数字加和即可,因为雷为1,非雷为0),并将雷的个数打印在该坐标处
    int count = GetMineCount(mine, x, y);
  • 判断游戏结束标志:
    游戏结束有两种情况
    1.踩到雷
    2.将全部除雷的坐标全部排查到
    如,9* 9的棋盘中,布置10个雷的情况下,该情况的结束标志是将9* 9-10=71个位置全部排查到,故设置win来判断,将其初始化为0,只要成功排查,win++,最后判断win是否等于71即可

其中,将雷的个数打印在坐标处时需要注意一个问题:

这是一个字符棋盘,里面存储的是字符,而将数字打印出来,需要将字符转化为数字

c 复制代码
show[x][y] = count + '0';

比如:

'0'-'0'=0 ('0'ASC码值为48)

'1'-'0'=1

'2'-'0'=2

反推回去即可

`

代码及注释如下:

game.h

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
//头文件的包含
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define EASY_COUNT 10//雷数

#define ROW 9//行
#define COL 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[ROW][COLS],char show[ROWS][COLS],int row,int col);

game.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//函数的定义
//初始化棋盘
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;
	for (j = 0;j <=col;j++) {
		printf("%d ", j);
	}
	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 SetMine(char mine[ROWS][COLS], int row, int col) {
	//布置十个雷--在mine数组的中间9*9的范围内,随机布置
	int count = EASY_COUNT;
	while (count) {
		int x = rand()%row+1;//返回值1~9
		int y = rand()%col+1;//返回值1~9
		if (mine[x][y] == '0'){
			mine[x][y]='1';
			count--;
		}
	}
}
int GetMineCount(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) {
	int x = 0, y = 0;
	printf("排查雷\n");
	int win = 0;
	while (win<row*col- EASY_COUNT) {
		printf("请输入要排查的坐标:\n");
		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");
					DisplayBoard(mine, ROW, COL);
					break;
				}
				else {
					//不是雷
					//统计(x,y)坐标周围有几个雷
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';//将数字转化为字符
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else {
				printf("该坐标已经被排查过,请重新输入\n");
			}
		}
		else {
			printf("输入的坐标非法,请重新输入\n");
		}	
	}
	if (win == row * col - EASY_COUNT) {
		printf("恭喜你排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

test.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu() {
	printf("*********************\n");
	printf("****** 1.play *******\n");
	printf("****** 0.exit *******\n");
	printf("*********************\n");
}
void game() {
	//完成扫雷游戏的逻辑
	char mine[ROWS][COLS];//存放布置好的雷的信息
	char show[ROWS][COLS];//存放排查出雷的信息
	//初始化棋盘
	//mine初始化为全'0'
	//show初始化为全'*'
	InitBoard(mine,ROWS,COLS,'0');
	InitBoard(show,ROWS,COLS,'*');
	//打印棋盘
	DisplayBoard(show, ROW, COL);
	
	//布置雷
	SetMine(mine,ROW,COL);
	//DisplayBoard(mine, ROW, COL);
	//排查雷
	FindMine(mine,show,ROW,COL);

}
void test() {
	int input = 0;
	srand((unsigned int)time(NULL));
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input) 
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏");
			break;
		default:
			printf("选择错误,重新选择");
			break;
		}
	} while (input);
}
int main() {
	//测试的函数
	test();
	return 0;
}

扫雷游戏的扩展

  • 是否可以选择游戏难度
    简单 9 * 9 棋盘, 10个雷
    中等16 *16棋盘,40个雷
    困难30 *16棋盘,99个雷
  • 如果排查位置不是雷,周围也没有雷,可以展开周围的一片(递归)
  • 是否可以标记雷
  • 是否可以加上排雷的时间显示

后续会逐渐完善

END...

"我走得很慢,但是我从来不会后退。"

相关推荐
阿巴斯甜4 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker5 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95276 小时前
Andorid Google 登录接入文档
android
黄林晴7 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
xiezhr7 小时前
米哈游36岁程序员被曝复工当晚猝死出租屋内
游戏·程序员·游戏开发
冬奇Lab19 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android