3

(C语言篇)扫雷的实现

 2 years ago
source link: https://blog.csdn.net/Autonmy_/article/details/121297922
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前言:本次扫雷分为三个文件,分别为test.c、game.h、game.c文件,其中test.c文件主要是用来实现扫雷的逻辑,game.c用于编写游戏的主要实现方法。
在这里插入图片描述

一、开始时的基本思维:

在这里插入图片描述

这里我们可以看到要实现初级的扫雷需要9 * 9的格子,所以需要使用一个二维数组,而我们需要创建两个棋盘,一个是用于放雷的(玩家不可见),一个是用于排查显示的。

在这里插入图片描述

二、进入游戏的逻辑(test.c文件中实现)

#include "game.h"


void menu() {
	printf("-------------欢迎进入超好玩的扫雷游戏---------------\n");
	printf("---------------       1.play       ---------------\n");
	printf("---------------       0.exit       ---------------\n");
	printf("--------------------------------------------------\n");
}
void test() {
	int input = 0;
	do {
		menu();//打印菜单
		printf("请输入1/0: ");
		scanf("%d", &input);
		printf("\n");
		switch (input) {
		case 1:
			printf("进入游戏\n");
			break;
		case 0:
			printf("退出游戏: \n");
			break;
		default:
			printf("你很调皮哦没有输入正确的数字,请重新输入!\n");
		}
	} while(input);
}
int main() {

	test();
	return 0;
 }

这里头文件的引用就不再介绍了讲三子棋的时候有说过。这里我们来看看效果:

在这里插入图片描述

这里我们可以看到进入游戏的逻辑没有问题,这时就可以把case 1:中的 printf(“进入游戏\n”);改为game函数了。

三、游戏的编写

1. 初始化棋盘

I. test.c

void game() {
	//创建两个字符数组
	char mine[ROWS][COLS] = { 0 };  //用于放雷
	char show[ROWS][COLS] = { 0 };  //用于存放显示不是雷的信息
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');  //这里我们把数组全部初始化为'0',代表没有雷  
	InitBoard(show, ROWS, COLS, '*');  //这里用'*'进行显示
	
}

II. game.h

//头文件的包含
#include <stdio.h>

//符号的声明
#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 a);

这里使用#define是方便于改变。如果想做难度高的扫雷可以随时改变棋盘大小。

III. game.c

#include "game.h"

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

2.打印棋盘

初始化完后我们就需要打印棋盘了。

I. test.c

void game() {
	//创建两个字符数组
	char mine[ROWS][COLS] = { 0 };  //用于放雷
	char show[ROWS][COLS] = { 0 };  //用于存放显示不是雷的信息
	//初始化棋盘
	InitBoard(mine, ROW, COL, '0');  //这里我们把数组全部初始化为'0',代表没有雷 
	InitBoard(show, ROW, COL, '*');  //这里用'*'进行显示
	//打印棋盘
	PrintBoard(mine, ROW, COL);
	PrintBoard(show, ROW, COL);
	
}

这里传的数组还是11* 11,因为我们只操作中间的9*9的数,所以在传行和列时只需要传大小为9的就行。

II. game.h

//头文件的包含
#include <stdio.h>

//符号的声明
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

//函数声明

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char a);
//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);

III. game.c

//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col) {
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++) {	
		for (j = 1; j <= col; j++) {	
			printf(" %c ", board[i][j]);
		}
		printf("\n");  //打印完一行需要换行
	}
}

这里我们可以看到棋盘打印出来了,但是这样的话玩家进行判断时还要数他是几行几列,有点麻烦所以可以加上坐标。

在这里插入图片描述

可以改为:

//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col) {
	int i = 0;
	int j = 0;
	//打印列号
	for (i = 0; i <= col; i++) {
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++) {
		printf("%d ", i); //打印行号
		for (j = 1; j <= col; j++) {
			
				printf("%c ", board[i][j]);
		}
		printf("\n");  //打印完一行需要换行

	}
}

接下来我们来看看结果:
在这里插入图片描述

3.布置雷

当我们实现棋盘的打印后就可以布置雷了

I. test.c

void game() {
	//创建两个字符数组
	char mine[ROWS][COLS] = { 0 };  //用于放雷
	char show[ROWS][COLS] = { 0 };  //用于存放显示不是雷的信息
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');  //这里我们把数组全部初始化为'0',代表没有雷 
	InitBoard(show, ROWS, COLS, '*');  //这里用'*'进行显示
	//打印棋盘
	//PrintBoard(mine, ROW, COL);
	//printf("\n");
	//PrintBoard(show, ROW, COL);

	//布置雷
	PutMine(mine, ROW, COL);
	PrintBoard(mine, ROW, COL); 
}

注意想要使用rand函数需要在test函数里加入:
srand((unsigned int)time(NULL));

II. game.h

//头文件的包含
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


//符号的声明
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define COUNT 10

//函数声明

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char a);
//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void PutMine(char mine[ROWS][COLS], int row, int col);

使用rand函数时需要包含#include <stdlib.h>这个头文件,time函数需要包含#include <time.h>头文件。

III. game.c

//布置雷
void PutMine(char mine[ROWS][COLS], int row, int col) {
	int count = 10;//10个雷
	while (count) {
		int x = rand() % row + 1;//生成1~9的随机数
		int y = rand() % col + 1;
		if (mine[x][y] == '0') {		//排除1重复在一个位置的可能
			mine[x][y] = '1';
			count--;
		}
	}
}

通过下图可以看出我们成功的布置了10个雷:

在这里插入图片描述

4.排查雷

I. test.c

void game() {
	//创建两个字符数组
	char mine[ROWS][COLS] = { 0 };  //用于放雷
	char show[ROWS][COLS] = { 0 };  //用于存放显示不是雷的信息
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');  //这里我们把数组全部初始化为'0',代表没有雷
	InitBoard(show, ROWS, COLS, '*');  //这里用'*'进行显示
	//打印棋盘
	//PrintBoard(mine, ROW, COL);
	//printf("\n");
	//PrintBoard(show, ROW, COL);

	//布置雷
	PutMine(mine, ROW, COL);
	//PrintBoard(mine, ROW, COL);
	PrintBoard(show, ROW, COL);

	//排雷
	FineMine(mine, show, ROW, COL);
}

II. game.h

//头文件的包含
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


//符号的声明
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2


//函数声明

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char a);
//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void PutMine(char mine[ROWS][COLS], int row, int col);
//排雷
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

III. game.c

//排雷

//判断玩家输入坐标周围有几个雷
int mine_count(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');//周围有8格所以乘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 - 10) {  //当排了71次后就表示赢了	
		printf("请输入坐标: ");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col) {  //限制输入1~9的数
			if (mine[x][y] == '1') {  //中雷
				printf("恭喜你被雷砸上天了,祝你旅行愉快,游戏结束\n");
				PrintBoard(mine, row, col);//打印
				break;
			}
			else {
				int num = mine_count(mine, x, y);  //判断玩家输入坐标周围有几个雷并且返回,需要用mine数组判断
				show[x][y] = num + '0';  //因为num是整型所以需要加一个'0'使其变为字符型。加了'0'后还是num这个数。
				PrintBoard(show, row, col);
				win++;
			}
		}
		else {
			printf("你输入的值不在范围内,请重新输入\n");
		}
	}
	if (win == row * col - 10) {
		printf("恭喜你,你成功了,剩下的都是雷\n");
		PrintBoard(mine, row, col);	//赢了打印雷在哪里
	}
}

对字符转化的思想及判断周围有几个雷的思想:
在这里插入图片描述在这里插入图片描述运行结果:
从图中可以看出,当输入坐标时,它就会显示周围有几个雷
在这里插入图片描述
踩雷时:
在这里插入图片描述
赢时:

为了方便这里我们可以在头文件用#define MINE_COUNT规定雷的总数,这样需要改时就在头文件改即可,为了快速测出赢了我们设置80给雷并且显示mine函数:
此时代码变为:
game.h

//头文件的包含
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


//符号的声明
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define MINE_COUNT 80

//函数声明

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char a);
//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void PutMine(char mine[ROWS][COLS], int row, int col);
//排雷
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game.c
这里涉及到用#define MINE_COUNT雷的改变为布雷时候和排雷时

//布置雷
void PutMine(char mine[ROWS][COLS], int row, int col) {
	int count = MINE_COUNT;
	while (count) {
		int x = rand() % row + 1;//生成1~9的随机数
		int y = rand() % col + 1;
		if (mine[x][y] == '0') {		//排除1重复在一个位置的可能
			mine[x][y] = '1';
			count--;
		}
	}
}

//排雷

//判断玩家输入坐标周围有几个雷
int mine_count(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');//周围有8格所以乘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 - MINE_COUNT) {  //当排了71次后就表示赢了	
		printf("请输入坐标: ");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col) {  //限制输入1~9的数
			if (mine[x][y] == '1') {  //中雷
				printf("恭喜你被雷砸上天了,祝你旅行愉快,游戏结束\n");
				PrintBoard(mine, row, col);//打印
				break;
			}
			else {
				int num = mine_count(mine, x, y);  //判断玩家输入坐标周围有几个雷并且返回,需要用mine数组判断
				show[x][y] = num + '0';  //因为num是整型所以需要加一个'0'使其变为字符型。加了'0'后还是num这个数。
				PrintBoard(show, row, col);
				win++;
			}
		}
		else {
			printf("你输入的值不在范围内,请重新输入\n");
		}
	}
	if (win == row * col - MINE_COUNT) {
		printf("恭喜你,你成功了,剩下的都是雷\n");
		PrintBoard(mine, row, col);//赢了打印雷在哪里
	}
}

如图可以看到当我们输入3 8时就赢了:

在这里插入图片描述赢了:
在这里插入图片描述

四、完整代码

1.test.c

#include "game.h"
void game() {
	//创建两个字符数组
	char mine[ROWS][COLS] = { 0 };  //用于放雷
	char show[ROWS][COLS] = { 0 };  //用于存放显示不是雷的信息
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');  //这里我们把数组全部初始化为'0',代表没有雷
	InitBoard(show, ROWS, COLS, '*');  //这里用'*'进行显示
	//打印棋盘
	//PrintBoard(mine, ROW, COL);
	//printf("\n");
	//PrintBoard(show, ROW, COL);

	//布置雷
	PutMine(mine, ROW, COL);
	PrintBoard(mine, ROW, COL);
	printf("\n");
	PrintBoard(show, ROW, COL);

	//排雷
	FineMine(mine, show, ROW, COL);
}

void menu() {
	printf("-------------欢迎进入超好玩的扫雷游戏-------------\n");
	printf("---------------       1.play       ---------------\n");
	printf("---------------       0.exit       ---------------\n");
	printf("--------------------------------------------------\n");
}
void test() {
	int input = 0;
	srand((unsigned int)time(NULL));
	do {
		menu();//打印菜单
		printf("请输入1/0: ");
		scanf("%d", &input);
		printf("\n");
		switch (input) {
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏: \n");
			break;
		default:
			printf("你很调皮哦没有输入正确的数字,请重新输入!\n");
		}
	} while(input);
}
int main() {

	test();
	return 0;
}

2.game.h

//头文件的包含
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


//符号的声明
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define MINE_COUNT 10

//函数声明

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char a);
//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void PutMine(char mine[ROWS][COLS], int row, int col);
//排雷
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

3.game.c

#include "game.h"


//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char a) {
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++) {	//这里一定要初始化全部,不然后面计算周围有几个雷时会出错。
		for (j = 0; j < cols; j++) {	
			board[i][j] = a;
		}
	}
}

//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col) {
	int i = 0;
	int j = 0;
	//打印列号
	for (i = 0; i <= col; i++) {
		printf("%d ", i);
	}
	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 PutMine(char mine[ROWS][COLS], int row, int col) {
	int count = MINE_COUNT;
	while (count) {
		int x = rand() % row + 1;//生成1~9的随机数
		int y = rand() % col + 1;
		if (mine[x][y] == '0') {		//排除1重复在一个位置的可能
			mine[x][y] = '1';
			count--;
		}
	}
}

//排雷

//判断玩家输入坐标周围有几个雷
int mine_count(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');//周围有8格所以乘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 - MINE_COUNT) {  //当排了71次后就表示赢了	
		printf("请输入坐标: ");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col) {  //限制输入1~9的数
			if (mine[x][y] == '1') {  //中雷
				printf("恭喜你被雷砸上天了,祝你旅行愉快,游戏结束\n");
				PrintBoard(mine, row, col);//打印
				break;
			}
			else {
				int num = mine_count(mine, x, y);  //判断玩家输入坐标周围有几个雷并且返回,需要用mine数组判断
				show[x][y] = num + '0';  //因为num是整型所以需要加一个'0'使其变为字符型。加了'0'后还是num这个数。
				PrintBoard(show, row, col);
				win++;
			}
		}
		else {
			printf("你输入的值不在范围内,请重新输入\n");
		}
	}
	if (win == row * col - MINE_COUNT) {
		printf("恭喜你,你成功了,剩下的都是雷\n");
		PrintBoard(mine, row, col);//赢了打印雷在哪里
	}
}

好了,扫雷就暂时讲到这里了,因博主能力有限,这次的扫雷小游戏还有很多可以优化的地方,如右键标记,输入一个坐标会展开一片等等。当然等博主再厉害点会优化的这些功能的。喜欢的可以点个赞哦。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK