扫雷C语言写法详解

        相信大家对扫雷一定都不陌生吧!但是你敢信仅仅使用一些C语言的初阶基础知识就能够制作一个扫雷简单小游戏?hhhhh,今天,我将带领大家一起走进扫雷,探究其基础算法奥秘。

一、基本思路

首先,既然是玩游戏,我们应该设计相应的菜单。

输入1后继续让玩家选择游戏难度:

我们在这里设计简单模式为6x6大小的面板,雷埋10个;中等模式为10x10大小的面板,雷埋30个;困难模式为14x14大小的面板,雷埋50个。

为了方便雷的布置与显示,我们设计了两张面板:show_board[ROW][COL]和mine_board[ROW][COL],其中show面板负责显示“空格”,mine面板负责记录周围雷的个数。

玩家通过输入每个格子所对应的坐标进行扫雷操作。

char** show_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4));//二维数组动态内存分配

for (int i = 0; i < ROW + grade * 4; i++) {
	show_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4));
	memset(show_board[i], ' ', (COL + grade * 4));//数组全部赋值为空格
}

char** mine_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4));

for (int i = 0; i < ROW + grade * 4; i++) {
	mine_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4));
	memset(mine_board[i], '0', (COL + grade * 4));//数组全部赋值为‘0’
}

 二、代码实现

Step1.画图

想要进行扫雷游戏,首先应该有扫雷界面的设计,如下:

我们建立Showboard函数进行面板的基本绘制:

static void Showboard(char **board,int grade)//面板制作
{
	printf(" ");
	for (int i = 1; i <= ROW-2+4*grade; i++) {
		printf(" %3d", i);
	}
	printf("\n");

	for (int i = 1; i <= ROW-2+4*grade; i++){
		printf("   ");
		for (int k = 1; k <= COL-2+4*grade; k++) {
			printf("----");
		}
		printf("\n");
		printf("%2d|",i);
		for (int j = 1; j <= COL-2+4*grade; j++){
			printf(" %c |",board[i][j]);
		}
		printf("\n");
	}
	printf("   ");
	for (int k = 1; k <= COL-2+4*grade; k++) {
		printf("----");
	}
	printf("\n");
}

 成果图如下:

Step2. 埋雷

埋雷应做到一下几点:

1.展示面板show_board(这里传参后以形参board替代)赋值为1(BOOM宏定义为1) ;

2.为了提高用户体验,在被炸后能够展示出雷的位置,我们又建立了一个lei_board数组用来显示,并在埋雷时将对应位置赋值为'*';

3.埋雷要具有随机性,所以这里引用rand函数(主函数要种随机数种子);

static void SetMines(char **board,char **lei_board,int grade)
{
	int i = 1;
	int x, y;
	while (i <= NUM+grade*20) {
		x = rand() % (ROW-2+4*grade) + 1;
		y = rand() % (COL-2+4*grade) + 1;
		if (board[x][y] != BOOM) {
			board[x][y] = BOOM;
			lei_board[x][y] = '*';
			i++;
		}
	}
}

Step3.计算周围雷的个数

当我们计算周围雷的个数时,自然而然地就会想到统计周围九宫格的雷的个数。如果要搜索的位置在面板中间,这很简单,但如果是以下这类情况,比如顶点格或者边格怎么办?如何知道该算哪个格?

 为了避免这种特殊情况所带来的问题,我们不如直接在外面再套一圈,对于各类面板(即二维数组)的建立也直接按照增大的来,这样就无需讨论边角的特殊性了。

统计函数直接通过简单的函数返回来实现:

static int CountMine(char **board,int x,int y)
{
	return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
		board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + \
		board[x + 1][y] + board[x + 1][y + 1] - 8 * '0';
}

 三、完整代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>

#define BOOM '1'
#define ROW 8
#define COL 8
#define NUM 10

static void SetMines(char **board,char **lei_board,int grade)//埋雷
{
	int i = 1;
	int x, y;
	while (i <= NUM+grade*20) {
		x = rand() % (ROW-2+4*grade) + 1;
		y = rand() % (COL-2+4*grade) + 1;
		if (board[x][y] != BOOM) {
			board[x][y] = BOOM;
			lei_board[x][y] = '*';
			i++;
		}
	}
}
static void Showboard(char **board,int grade)//面板制作
{
	printf(" ");
	for (int i = 1; i <= ROW-2+4*grade; i++) {
		printf(" %3d", i);
	}
	printf("\n");

	for (int i = 1; i <= ROW-2+4*grade; i++){
		printf("   ");
		for (int k = 1; k <= COL-2+4*grade; k++) {
			printf("----");
		}
		printf("\n");
		printf("%2d|",i);
		for (int j = 1; j <= COL-2+4*grade; j++){
			printf(" %c |",board[i][j]);
		}
		printf("\n");
	}
	printf("   ");
	for (int k = 1; k <= COL-2+4*grade; k++) {
		printf("----");
	}
	printf("\n");
}
static int CountMine(char **board,int x,int y)//统计周围雷的数目
{
	return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
		board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + \
		board[x + 1][y] + board[x + 1][y + 1] - 8 * '0';
}

void Game(int grade)//游戏函数,grade为游戏难度等级
{
	
	char** show_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4));
	for (int i = 0; i < ROW + grade * 4; i++) {
		show_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4));
		memset(show_board[i], ' ', (COL + grade * 4));
	}
	char** mine_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4));
	for (int i = 0; i < ROW + grade * 4; i++) {
		mine_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4));
		memset(mine_board[i], '0', (COL + grade * 4));
	}
	char** lei_board = (char**)malloc(sizeof(char*) * (ROW + grade * 4));
	for (int i = 0; i < ROW + grade * 4; i++) {
		lei_board[i] = (char*)malloc(sizeof(char) * (COL + grade * 4));
		memset(lei_board[i], ' ', (COL + grade * 4));
	}
	
	SetMines(mine_board,lei_board,grade);
	int x = 0, y = 0;
	int total = 0;
	while (1)
	{
		
		Showboard(show_board, grade);
		printf("请输入坐标:");
		//printf("%d", '*');
		scanf("%d %d", &x, &y);
		if (!(x > 0 && x <= ROW + 4 * grade - 2 && y > 0 && y <= COL + 4 * grade - 2)) {
			printf("扫雷的位置有问题!\n");
			continue;
		}
		if (show_board[x][y] != ' ') {
			printf("该位置已经扫过了!\n");
			continue;
		}
		if (mine_board[x][y] == '1') {
			printf("对不起,你被炸死了!\n");
			Showboard(lei_board, grade);
			break;
		}
		else {
			int count = CountMine(mine_board, x, y);
			show_board[x][y] = count + '0';
			total++;
			system("cls");
		}
		if ((ROW - 2) * (COL - 2) - total <= NUM) {
			printf("恭喜你,游戏通过!\n");
			break;
		}
	}
	for (int i = 0; i < ROW + grade * 4; i++) {
		free(show_board[i]);
	}
	free(show_board);
	for (int i = 0; i < ROW + grade * 4; i++) {
		free(mine_board[i]);
	}
	free(mine_board);
	for (int i = 0; i < ROW + grade * 4; i++) {
		free(lei_board[i]);
	}
	free(lei_board);
}

void Menu()
{
	printf("#########################################\n");
	printf("##                 1.play              ##\n");
	printf("##                 0.exit              ##\n");
	printf("#########################################\n");
}

int main()
{
	srand((unsigned long)time(NULL));
	int quit = 0;
	while (!quit)
	{
		int select;
		Menu();
		printf("请输入游戏选项:");
		scanf("%d", &select);
		switch (select)
		{
		case 1:
			printf("#########################################\n");
			printf("##                 1.easy              ##\n");
			printf("##                 2.middle            ##\n");
			printf("##                 3.difficult         ##\n");
			printf("#########################################\n");
			printf("请输入游戏难度:");
			scanf("%d", &select);
			switch (select)
			{
			case 1:
				Game(0);
				break;
			case 2:
				Game(1);
				break;
			case 3:
				Game(2);
				break;
			}
			break;
		case 0:
			quit = 1;
			printf("感谢使用!");
			break;
		default:
			printf("输入有误,请重新输入!\n");
			break;
		}

	}
	
}

        期待大家在这个代码的基础上加入更多创新与改进,写出用户体验感更好,更加智能高端的扫雷程序!!!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值