简易扫雷游戏的实现 基于控制台 初版

一、游戏规则

规则非常简单:

  • 游戏盘面上随机布置有一定数量的地雷
  • 玩家需要通过输入坐标,来开启格子,避免踩到地雷
  • 开启的格子会显示周围8个方向上地雷的数量
  • 步步为营,最终排查掉所有非地雷格子即为胜利

二、代码解析

1. 定义游戏盘面

首先需要定义游戏盘面的大小,也就是行数和列数。同时定义一个稍大一点的数组,用于打印行号和列号:

#define R 9 
#define C 9
#define RS 11
#define CS 11

此外,定义非地雷格子数方便后续调整和测试:

//定义非地雷格子数
#define TOTAL_CLEAR_BLOCKS 71
2. 初始化游戏盘面

通过一个初始化函数,可以把游戏盘面所有的元素都设置为指定字符,比如:

void InitBoard(char arr[RS][CS], int r, int c, char format) {
  for (int i = 0; i < r; i++) {
    for (int j = 0; j < c; j++) {
      arr[i][j] = format;
    }
  }
}

这样就可以分别初始化隐藏盘面和显示盘面了:

InitBoard(under, RS, CS, '0'); 
InitBoard(uncover, RS, CS, '*');
3. 打印游戏盘面

打印游戏盘面也封装成函数,每次根据需要打印隐藏盘面或显示盘面:

void PrintBoard(char arr[RS][CS], int r, int c) {
	printf("-------------------\n");
	
	//打印列号
	for (int i = 0; i <= c; i++) {
		printf("%d ", i);
	}
	printf("\n");

	//打印行号和盘面
	for (int i = 1; i <= r; i++) {
		printf("%d ", i);
		for (int j = 1; j <= c; j++) {
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
	printf("-------------------\n");
}
4. 设置地雷

通过随机数生成地雷坐标,保存在隐藏盘面:

void Set(char under[RS][CS], int r, int c) {
	int x = 1, y = 1;
	int num_of_bombs = r * c - TOTAL_CLEAR_BLOCKS;//定义设置地雷的总数
	while (num_of_bombs) {
		//生成1~9的随机数分别作为设置地雷的x、y坐标
		x = rand() % 9 + 1;
		y = rand() % 9 + 1;
		if (under[x][y] != '1') {
			under[x][y] = '1';
			num_of_bombs--;
		}
	}
}
5. 排查扫雷

这是游戏的核心逻辑。输入坐标后,先判断是否踩雷,如果是则重新开始。

如果不是,计算周围8格的地雷数量,更新显示盘面,进入循环排查直到开启全部非地雷格子。

void Find(char under[RS][CS], char uncover[RS][CS], int r, int c) {
	int x = 1, y = 1;
	int count = 0;
	while (count < TOTAL_CLEAR_BLOCKS) {
		printf("请输入你要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x > 0 && x < 10 && y>0 && y < 10) {
			if (under[x][y] == '1') {
				printf("你已触雷,所有雷排布如下:\n");
				PrintBoard(under, R, C);
				printf("请重新开始:\n");
				menu();
				break;
			}
			else {
				int around = 0;
				//计算周围8格的地雷数量
				around = under[x - 1][y - 1] + under[x][y - 1] + under[x + 1][y - 1] + under[x - 1][y]
					+ under[x + 1][y] + under[x - 1][y + 1] + under[x][y + 1] + under[x][y] - 8 * '0';
				uncover[x][y] = around + '0';
				PrintBoard(uncover, R, C);
				count++;
			}
		}
		else {
			printf("输入坐标非法,请重新输入\n");
		}
	}
	if (count == TOTAL_CLEAR_BLOCKS) {
		printf("恭喜你排雷成功\n");
	}
}

其中,因为盘面元素为 char 类型,故涉及到整数与对应 char 类型字符的转换,整数转到其指示的字符只需要加上'0'即可,而字符转到其指示的整数只需要减去'0'即可,举例如下: 

int num = 3;
char ch = 3 + '0'; // ch为'3'

char ch2 = '9';
int num2 = ch2 - '0'; // num2的值为9
6. 扫雷游戏核心函数
void game() {
	char under[RS][CS];
	char uncover[RS][CS];

	InitBoard(under, RS, CS, '0');
	InitBoard(uncover, RS, CS, '*');

	printf("\n");
	PrintBoard(uncover, R, C);
	
	Set(under, R, C);
	PrintBoard(under, R, C);
	Find(under, uncover, R, C);

}
7. 菜单打印函数
void menu() {
	printf("------------------------------------------\n");
	printf("-------------  1.开始游戏  ---------------\n");
	printf("-------------  0.退出游戏  ---------------\n");
	printf("------------------------------------------\n");
}
8. 主函数流程

主函数中包括:

  • 调用扫雷游戏核心函数
  • 循环直到玩家选择退出
int main() {
	int input = 0;
	srand((unsigned int) time(NULL));
	do {
		menu();
		printf("开始游戏(1)或退出游戏(0),请输入:");
		scanf("%d", &input);
		if (input == 1) {
			game();
		}
		if (input == 0) {
			printf("已退出游戏\n");
		}
	} while (input);
	return 0;
}
9. 头文件定义与声明
#define R 9
#define C 9
#define RS 11
#define CS 11

//定义非地雷格子数
#define TOTAL_CLEAR_BLOCKS 71

void menu();
void game();

//游戏内函数声明
void InitBoard(char arr[RS][CS], int r, int c, char format);
void PrintBoard(char arr[RS][CS], int r, int c);
void Set(char under[RS][CS], int r, int c);
void Find(char under[RS][CS], char uncover[RS][CS], int r, int c);

三、后续展望

上述实现较为简单,后续可以进一步优化和拓展,下方列举了一些方向以供参考:

  1. 错误处理:在代码中添加一些错误处理逻辑,以便处理无效输入或其他潜在的错误情况,而不是简单地假定输入都是有效的。

  2. 随机数生成:使用rand()函数生成随机数是可以的,但请注意,它可能不够随机,尤其是在某些情况下。你可以考虑使用更现代的随机数生成库,如C++11引入的<random>库。

  3. 更多的游戏规则:扩展游戏以包括更多的规则,例如,添加难度级别、允许玩家标记潜在雷区等。

  4. 计时功能:添加一个计时器,以测量玩家完成游戏所需的时间。

  5. 图形界面:考虑将游戏扩展为具有图形用户界面(GUI),这将使游戏更具吸引力和可玩性。

  6. 保存和加载游戏:允许玩家保存游戏状态,并在以后恢复游戏,这将增加游戏的可玩性。

  7. 代码清洁和格式化:确保你的代码符合一致的代码风格,并定期进行代码清洁,以删除不再使用的代码和注释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值