入门级c语言小游戏------实现扫雷(详解)

欢迎打开本篇文章还记得下幅图吗?还记得当年完成下图和朋友吹嘘的场景吗?博主可是用来打发了无数时光,我们学习的c语言也是可以实现简单的扫雷的小游戏,一起来看看吧!
在这里插入图片描述

前言

本次扫雷分为三个文件,分别为test.c、game.h、game.c文件,其中game.h主要是声明我们所使用的头文件、函数等,test.c文件主要是用来实现扫雷的逻辑,game.c用于编写游戏的主要实现方法。
如图:
在这里插入图片描述

一、基本实现思想

在使用前,我们要设定两个数组,一个用来放置雷(玩家不可见),而另一个用来供玩家排查,在实现99的初级扫雷游戏之前,我们需要用二位数值来实现。
如果我们想排查3
3位置的雷,我们只需要判断周围有多少雷打印出来即可,但如果我们想排查9*9的雷,我们就需要考虑在边界处数组越界的情况,为了防止越界,我们可以考虑用11*11数组的形式来实现9*9的雷盘,最外围一组我们不进行任何操作的设定,这样即可防止数组越界的发生。

二、扫雷总体逻辑

2.1菜单函数

void menu() {
    
    
	printf("-------------欢迎进入超好玩的扫雷游戏---------------\n");
	printf("---------------       1.play       ---------------\n");
	printf("---------------       0.exit       ---------------\n");
	printf("--------------------------------------------------\n");
}

2.2 扫雷主体逻辑函数

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);
}

2.3主函数

int main() {
    
    

	test();
	return 0;
}

2.4效果展示

在这里插入图片描述
我们可以看到逻辑上是没有任何问题的,接下来我们具体实现,冲

三、具体实现

3.1 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);

3.2初始化棋盘

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

3.3打印棋盘

我们既然要打印,就把打印函数直接放到game中实现,修改如下:

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的就行。

把函数声明继续加到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);

打印函数

//打印棋盘
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.4布置雷

继续修改game函数,以便于后续代码的实现

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));//便于我们的随机数是根据时间戳生成,确保真正的随机:
使用rand函数时需要包含#include <stdlib.h>这个头文件,time函数需要包含#include <time.h>头文件。

我们继续声明该函数到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);

布置雷函数实现:

//布置雷
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--;
		}
	}
}

** 布置雷展示**
在这里插入图片描述

3.5排查雷

继续修改game函数:

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);
}

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);

排雷函数实现如下:

//排雷

//判断玩家输入坐标周围有几个雷
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);	//赢了打印雷在哪里
	}
}

注:判断周围有几个雷,我们需要按照一定的顺序判断,我们将雷设置为1,所以我们返回坐标中的值即可,同时我们需要将字符型转换为整形,所以我们-‘0’即可得到我们需要的值
如下图:
在这里插入图片描述
为了方便这里我们可以在头文件game.h用#define MINE_COUNT规定雷的总数,方便我们后续的可读性

//头文件的包含
#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);

//布置雷
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);//赢了打印雷在哪里
	}
}

我们这时候就可以打印我们布雷的雷盘,并通过我们自己的手段赢上一局,来检测我们的代码是否可行!

四、整体函数实现

4.1 text.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;
}

4.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);

4.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);//赢了打印雷在哪里
	}
}

总结

总的来说,扫雷这个小游戏值得优化的地方还是很多,比如类似真正的扫雷可以鼠标点击查雷,可以一次排查一大片雷区等等,如果有小伙伴感兴趣,还清留下一个不要钱的赞支持博主后续的优化。

猜你喜欢

转载自blog.csdn.net/m0_65038072/article/details/127498646