C语言实现扫雷(初阶)


问题简述

用C语言实现扫雷游戏


一、大概思路

1.在我们开始设计扫雷面板前,要有一个菜单选择开始游戏或退出游戏,玩完一把后仍然有菜单选择。
2.我们可以打开网页版初阶扫雷面板,它是一个9*9的格子面板,这时我们能联想到二维数组。
3.因为扫雷是先有面板选择坐标,选择后再把含有排除雷的数量的面板打印出来,因此要创建两个二维数组,但需要考虑的是,如果在扫雷面板最边上排雷,排雷的坐标可能对于我们创建的数组已经越界,这是不可取的。因此我们还要有行与列各11的扫雷面板(如图所示)。并且将其中一个二维数组都放0,另一个都用‘ * ’号来代表没有排雷的区域。
在这里插入图片描述

4.随机设置雷的坐标,因为要随机则涉及到rand与srand函数,并且设置地雷的区域是此前没有设置地雷的区域,坐标不能重复,用‘1’代表雷,‘0’代表没有雷的区域。
5.设置好地雷后要进行排雷,如果在选择的坐标其边上5个的区域内有雷,则必须在选择的区域处将其边上5个区域的雷数显示出来,而且数字1与地雷‘1’要区分开来。
6.判断是否踩雷,如果全部雷都排出来,则判断成功,如果踩到了雷,则直接判断失败,如果既没有排完雷也没有踩雷,则游戏继续。

二、基本流程

1.打印游戏菜单

我们要求的是开始前选择是否开始游戏,游戏结束时不关闭页面重新进入菜单。

void menu()
{
	printf("************************\n");
	printf("*********1.play*********\n");
	printf("*********0.exit*********\n");
	printf("************************\n");
}
int main
{
do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("请重新选择\n");
			break;
		}
	} while (input);
	}

2.初始化扫雷面板

先建立两个不同的字符数组,再将其中一个数组都放入字符0,为了函数的可修改性,将数组的行与列在头文件中设置,再在源文件中包含头文件,函数实现前首先要在头文件中声明。

void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

头文件处声明与定义:

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void InitBoard(char board[ROWS][COLS], int rows, int cols);//初始化棋盘

3.打印设置好的扫雷面版

因为一开始我们并没有排雷,因此要将游戏面板上的所有坐标都先用‘ * ’号进行覆盖,选择后再把排出雷的数量或雷打印出来。为了玩家在输入坐标时方便,我们可以在扫雷面板的最上方与最左方将行数与列数标出来。

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("---------------\n");
	for (i = 0; i <= 9; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ",i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("--------------\n");
}

头文件处进行声明

void DisplayBoard(char Board[ROWS][COLS], int rows, int cols);//打印棋盘

4.随机设置雷的坐标

根据扫雷游戏规则,在初阶扫雷面板中最多能设置10个雷,并且要随机与不重复,因此在主函数中我们设置种子,让电脑随机生成坐标放入地雷。

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] != '1')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

头文件处进行声明

void SetMine(char board[ROW][COL], int row, int col);//设置地雷

5.进行排雷并判断输赢

当雷已经随机设置好后,我们要开始排雷。选择的坐标(不能输入非法坐标)在围绕其旁边的8个坐标内将雷的个数打印出来。因为一个扫雷面板只有10个雷,而总共有81个坐标,则还有71个坐标没有设置雷,当我们排的雷达到10个后则成功。最后无论成功与失败都要打印扫雷面板上所以雷的位置。
极其需要注意的点:因为我们创建的是字符类型的数组,因此我们在打印排出雷的数量的时候要加上字符0,因为数字个位数加上字符0都会变为字符数,这样才符合我们创建的数组类型。

void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	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 (mine[x][y] == '1')
			{
				printf("你被炸死了\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);
				show[x][y] = count+'0';
				DisplayBoard(show , ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

三、拓展衍生

测试发现代码效果没有问题后,我们可以拓展出扫雷面板更大、如何在第一次排雷时不踩雷、倒计时等问题,如果把这些问题解决对自己的代码逻辑会有很大的提升。

四、总代码展示

1.头文件代码

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

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10

void InitBoard(char board[ROWS][COLS], int rows, int cols);//初始化棋盘

void DisplayBoard(char Board[ROWS][COLS], int rows, int cols);//打印棋盘

void SetMine(char board[ROW][COL], int row, int col);//设置地雷

void FineMine(char mine[ROW][COL], char show[ROW][COL],int row, int col);//找地雷

int  GetMineCount(char mine[ROWS][COLS], int x, int y);

2.游戏实现代码

#include "game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("---------------\n");
	for (i = 0; i <= 9; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ",i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("--------------\n");
}

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] != '1')
		{
			board[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][y + 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] +
		mine[x + 1][y - 1] +
		mine[x - 1][y + 1]-8*'0';
}

void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	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 (mine[x][y] == '1')
			{
				printf("你被炸死了\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);
				show[x][y] = count+'0';
				DisplayBoard(show , ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

3.主函数代码

#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];
	InitBoard(mine, ROWS, COLS,'0');
	InitBoard(show, ROWS, COLS,'*');
	
	DisplayBoard(show, ROW, COL);
	SetMine(mine, ROW, COL);
	FineMine(mine,show, ROW, COL);
}
int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

五、代码效果展示

在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zjruiiiiii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值