C语言初阶之扫雷

目录

扫雷

准备环境

大致思路分析

编写主函数

重点塑造的game.c

1.game

2.board

3.playboard

4.board2

5.play

6.win

7.clearance


扫雷

hello!各位小伙伴们,今天小春宝将给大家分享扫雷,扫雷其实并没有大家想象中那么困难,接下来,教大家如何创建一个扫雷项目

准备环境

再写扫雷之前,我们得新建一个项目和三个文件

1.game.h

2.game.c

3.test.c

老规矩,先给大家献上头文件的内容

#ifndef __GAME_H__
#define __GAME_H__
#define  _CRT_SECURE_NO_WARNINGS 1
#define H 9
#define L 9
#define N 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void menu();
void game();
void board(char board[H][L], int x, int y);
void playboard(char board[H][L], int x, int y);
void board2(char arr1[H][L], int x, int y, int a, int b);
void play(char arr[H][L], char arr1[H][L], int x, int y);
int win(char arr[H][L], int x, int y);
void clearance(char arr[H][L], char arr1[H][L], int a, int b, int x, int y);
#endif 

大致思路分析

扫雷与三子棋不同,我们得有一个大致的框架才能够顺利的开始扫雷的构建,扫雷游戏的玩耍是翻开遮蔽的地方,如果是雷我们就被炸死了,如果不是会告诉我们附近是否有雷,这个时候我们需要两个棋盘,一个棋盘是给玩家看的,一个棋盘是实际上的棋盘,这个棋盘既要有雷,也要有提示雷的信息,为了防止用户第一步就被炸死了,我们需要在下完的第一步才确定雷的位置,为了尽量还原游戏的功能,我们可以增加标记这一功能来确定雷的位置。

编写主函数

看过三子棋的小伙伴们,应该对主函数的构建并不陌生,因为三子棋的主函数构建也是如出一辙,话不多说,直接上代码
 


#include"game.h"
void menu() {
	printf("**********************n");
	printf("****1.play 0.exit*****n");
	printf("**********************n");
}
int main() {
	int n;
	do {
		menu();
	a:
		printf("请选择:");
		scanf("%d", &n);
		switch (n)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出程序n");
			break;
		default:
			printf("输出错误,请重新输入n");
			goto a;
		}
	} while (n);
	return 0;
}

重点塑造的game.c

1.game

由于game函数本体十分简单,这里直接给大家上game

void game() {
	char arr[H][L] = { 0 };
	char arr1[H][L] = { 0 };
	int n;
	printf("扫雷游戏即将开始,敬请期待n");
	board(arr, H, L);
	playboard(arr, H, L);
	n = 1;
	while (n)
	{
		play(arr, arr1, H, L);
		n = win(arr, H, L);
	}
}

2.board

borad函数是初始化那个给玩家看的棋盘,他的载体是board[9][9]
为了方便修改棋盘内容,我们定义两个常量
H代表行,L代表列,我们今天要实现的扫雷是一个9*9十个雷的棋盘
为了一种什么感,我们选择'*'来给大家看到
void board(char board[H][L], int x, int y) {
	int i, j;
	for (i = 0; i < x; i++)
		for (j = 0; j < y; j++)
			board[i][j] = '*';
}

3.playboard

接下来又是今天的一个难题,在我看来,扫雷的棋盘相比于三子棋的棋盘难度更高些,实现这个棋盘需要大家不断的尝试和调整,直接上我们要的效果

首先我们先得打印而不去管那些数字,数字是为了提高用户体验之后加的
void playboard(char board[H][L], int x, int y) {
	int i, j;
	for (i = 0; i < x; i++) {

		for (j = 0; j < y; j++) {
			printf("|---");
		}
		printf("|n");
		for (j = 0; j < y; j++) {
			printf("| %c ", board[i][j]);

		}
		printf("|n");

	}
	for (j = 0; j < y; j++) {
		printf("|---");
	}
	printf("|n");
}

 这个是效果,但这个棋盘太大,我们需要数字来提示用户,添加数组这一步大家一定要多加尝试  

void playboard(char board[H][L], int x, int y) {
	int i, j,k;
	for (k = 0; k < x + 1; k++) {
		if (k == 0)
			printf("%d  ", k);
		else printf("%d   ", k);
	}
	printf("n");

	for (i = 0; i < x; i++) {
		printf(" ");
		for (j = 0; j < y; j++) {
			printf("|---");
		}
		printf("|n");
		printf("%d", i + 1);
		for (j = 0; j < y; j++) {
			printf("| %c ", board[i][j]);

		}
		printf("|n");

	}
	printf(" ");
	for (j = 0; j < y; j++) {
		printf("|---");
	}
	printf("|n");
}

这样之后扫雷就是完全体了,当然大家也可以靠着自己的意愿进行修改,我的这只是一个参考 

4.board2

首先我们暂时以A代表雷,每个字符暂定为0,只要周围有雷就加1
因为雷是随机的,我们这个时候需要随机值rand来协助我们完成
void board2(char arr1[H][L], int x, int y, int a, int b) {//a,b是用户第一次扫雷的位置的坐标
	int i, j, k, m, n;
	srand((unsigned)time(NULL));
	for (i = 0; i < x; i++)
		for (j = 0; j < y; j++)
			arr1[i][j] = '0';
	for (k = 0; k < N; k++)
	{
	a:
		i = rand() % x;
		j = rand() % y;
		if (arr1[i][j] != 'A' && i != a && j != b)
			arr1[i][j] = 'A';
		else
			goto a;
		for (m = i - 1; m <= i + 1; m++) {
			for (n = j - 1; n <= j + 1; n++) {
				if (m < x && m >= 0 && n < y && n >= 0 && arr1[m][n] != 'A')
					arr1[m][n]++;
			}
		}//这两层循环是用来给雷旁边的字符都加一的,并且我们需要判断该位置的合法性和是不是雷
	}

}

5.play

我们得让用户选择操作,开始扫雷,进行标记并且取消标记,开始扫雷
我们先来实现扫雷功能
void play(char arr[H][L], char arr1[H][L], int x, int y) {
	int i, j, n;
	static int k = 0;
b:	printf("(1.标记 0.开始扫雷 2.取消标记 )请选择:");
	scanf("%d", &n);
	switch (n)
	{
	case 0:
	a:	printf("(提示,以x y的形式输入,x代表行,y代表列)请输入你要扫的坐标:");
		scanf("%d%d", &i, &j);
		if (k < 1) {
			board2(arr1, x, y, i - 1, j - 1);
			k++;
		}
		if (i >= 1 && i <= x && j >= 1 && j <= 9)
		{
			if (arr[i - 1][j - 1] == '*')
				arr[i - 1][j - 1] = arr1[i - 1][j - 1];
			else {
				printf("该位置无法进行扫雷操作,请重新输入n");
				goto a;
			}
		}
		else
		{
			printf("输入坐标非法,请重新输入n");
			goto a;
		}
		break;
	case 1:
		break;
	case 2:
		break;
	default:
		printf("选择错误,请重新选择n");
		goto b;

	}
	system("cls");
	playboard(arr, H, L);
}


这里面包括了play函数的框架,这个时候我们再来进行标记的编写,我们约定被标记过的雷用'*'来表示
接下来我们直接编写case 1中的内容
c:	printf("请选择你要标记的坐标(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d %d", &i, &j);
		if (arr[i - 1][j - 1] == '*')
		{
			arr[i - 1][j - 1] = '#';
			printf("标记成功n");
		}
		else {
			printf("输出错误,请重新输入n");
			goto c;
		}
		break;
接着便是标记以后,若是用户觉得标记错误或者是不小心标记了,我们可以随时让用户选择取消标记
	printf("请选择你要取消标记的坐标(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d%d", &i, &j);
		if (arr[i - 1][j - 1] == '#')
		{
			printf("取消成功n");
			arr[i - 1][j - 1] = '*';
		}
		else {
			printf("取消标记失败n");
			goto b;
		}
//为预防用户误点取消标记,而当还未进行标记时就一直出不来了,所以避免这种情况,我们选择让用户直
//接回到b标记点的位置来重新选择操作
//接下来我们组装一下便可得到play
void play(char arr[H][L], char arr1[H][L], int x, int y) {
	int i, j, n;
	static int k = 0;
b:	printf("(1.标记 0.开始扫雷 2.取消标记 )请选择:");
	scanf("%d", &n);
	switch (n)
	{
	case 0:
	a:	printf("(提示,以x y的形式输入,x代表行,y代表列)请输入你要扫的坐标:");
		scanf("%d%d", &i, &j);
		if (k < 1) {
			board2(arr1, x, y, i - 1, j - 1);
			k++;
		}
		if (i >= 1 && i <= x && j >= 1 && j <= 9)
		{
			if (arr[i - 1][j - 1] == '*')
				arr[i - 1][j - 1] = arr1[i - 1][j - 1];
			else {
				printf("该位置无法进行扫雷操作,请重新输入n");
				goto a;
			}
		}
		else
		{
			printf("输入坐标非法,请重新输入n");
			goto a;
		}
		break;
	case 1:
	c:	printf("请选择你要标记的坐标(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d %d", &i, &j);
		if (arr[i - 1][j - 1] == '*')
		{
			arr[i - 1][j - 1] = '#';
			printf("标记成功n");
		}
		else {
			printf("输出错误,请重新输入n");
			goto c;
		}
		break;
	case 2:
		printf("请选择你要取消标记的坐标(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d%d", &i, &j);
		if (arr[i - 1][j - 1] == '#')
		{
			printf("取消成功n");
			arr[i - 1][j - 1] = '*';
		}
		else {
			printf("取消标记失败n");
			goto b;
		}
		break;
	default:
		printf("选择错误,请重新选择n");
		goto b;

	}
	system("cls");
	playboard(arr, H, L);
}

这个play函数比较长,但是大家在编写play函数时千万不要着急,我们最后还会对play函数进行一次修改

6.win

我们不能无止境的扫雷,而win函数就是用于判断是否游戏结束的函数
int  win(char arr[H][L], int x, int y) {
	int i = 0, j = 0;
	int count = 0;
	for (i = 0; i < x; i++) {
		for (j = 0; j < y; j++) {
			if (arr[i][j] == 'A')
			{
				printf("很遗憾,你输了n");
				return 0;
			}
			else if (arr[i][j] == '*' || arr[i][j] == '#')
				count++;
		}
	}
	if (count > N)
		return 1;
	else
	{
		printf("恭喜你,你赢了n");
		return 0;
	}
}
//根据我们编写的game函数可知win返回0的时候游戏继续,返回1游戏将继续

7.clearance

其实扫雷写到这里就可以结束了,但是如果就这样结束可能会让大家玩的很累,扫雷还有一种性质,只要旁边没有雷就会推开一片,然后不断的推开,知道旁边有雷,这个操作需要使用递归的思想,所以希望大家在编写这个函数时一定要多加思考,切勿盲目的编写,而这个函数的出现迫使我们不得不对play也进行修改

我们先来设计一下clearance函数
void clearance(char arr[H][L], char arr1[H][L], int a, int b, int x, int y) {
	int m,n;
	for (m = a ; m <= a+2; m++) {
		for (n = b; n <= b + 2; n++) {
			if (m >= 0 && m < x && n < y && n >= 0) {
				if (arr1[m][n] == '0' && arr[m][n] == '*')
				{
					arr[m][n] = arr1[m][n];
					clearance(arr, arr1, m - 1, n - 1, x, y);

				}
				else if (arr[m][n] != '#')
					arr[m][n] = arr1[m][n];
			}
		}


	}



}
然后我们再对play函数进行小小的修改
a:	printf("请选择你要扫的位置(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d %d", &i, &j);
		if (k < 1) {
			board2(arr1, H, L, i - 1, j - 1);
			k++;
		}
		if (i <= x && i >= 1 && j <= y && j >= 1) {
			if (arr[i - 1][j - 1] == '*')
			{
				arr[i - 1][j - 1] = arr1[i - 1][j - 1];
				if (arr[i - 1][j - 1] == '0')
					clearance(arr, arr1, i - 2, j - 2, H, L);
			}
			else {

				printf("该位置已经扫过,请重新输入n");
				goto a;
			}
		}
		else
		{
			printf("位置错误,请重新输入n");
			goto a;
		}
将case 0中的内容进行以下修改

当你看完这里,今天的扫雷就实现完成了,看完之后,大家应该可以做出属于自己的扫雷,最后送上完整的game.c

如果有需要完整的代码的也可以上我的码云去寻找

#include"game.h"
void board(char board[H][L], int x, int y) {
	int i, j;
	for (i = 0; i < x; i++)
		for (j = 0; j < y; j++)
			board[i][j] = '*';
}
void playboard(char board[H][L], int x, int y) {
	int i, j,k;
	for (k = 0; k < x + 1; k++) {
		if (k == 0)
			printf("%d  ", k);
		else printf("%d   ", k);
	}
	printf("n");

	for (i = 0; i < x; i++) {
		printf(" ");
		for (j = 0; j < y; j++) {
			printf("|---");
		}
		printf("|n");
		printf("%d", i + 1);
		for (j = 0; j < y; j++) {
			printf("| %c ", board[i][j]);

		}
		printf("|n");

	}
	printf(" ");
	for (j = 0; j < y; j++) {
		printf("|---");
	}
	printf("|n");
}
void board2(char arr1[H][L], int x, int y, int a, int b) {
	int i, j, k, m, n;
	srand((unsigned)time(NULL));
	for (i = 0; i < x; i++)
		for (j = 0; j < y; j++)
			arr1[i][j] = '0';
	for (k = 0; k < N; k++)
	{
	a:
		i = rand() % x;
		j = rand() % y;
		if (arr1[i][j] != 'A' && i != a && j != b)
			arr1[i][j] = 'A';
		else
			goto a;
		for (m = i - 1; m <= i + 1; m++) {
			for (n = j - 1; n <= j + 1; n++) {
				if (m < x && m >= 0 && n < y && n >= 0 && arr1[m][n] != 'A')
					arr1[m][n]++;
			}
		}
	}

}

void play(char arr[H][L], char arr1[H][L], int x, int y) {
	int i, j, n;
	static int k = 0;
b:	printf("(1.标记 0.开始扫雷 2.取消标记 )请选择:");
	scanf("%d", &n);
	switch (n)
	{
	case 0:
	a:	printf("请选择你要扫的位置(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d %d", &i, &j);
		if (k < 1) {
			board2(arr1, H, L, i - 1, j - 1);
			k++;
		}
		if (i <= x && i >= 1 && j <= y && j >= 1) {
			if (arr[i - 1][j - 1] == '*')
			{
				arr[i - 1][j - 1] = arr1[i - 1][j - 1];
				if (arr[i - 1][j - 1] == '0')
					clearance(arr, arr1, i - 2, j - 2, H, L);
			}
			else {

				printf("该位置已经扫过,请重新输入n");
				goto a;
			}
		}
		else
		{
			printf("位置错误,请重新输入n");
			goto a;
		}
		break;
	case 1:
	c:	printf("请选择你要标记的坐标(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d %d", &i, &j);
		if (arr[i - 1][j - 1] == '*')
		{
			arr[i - 1][j - 1] = '#';
			printf("标记成功n");
		}
		else {
			printf("输出错误,请重新输入n");
			goto c;
		}
		break;
	case 2:
		printf("请选择你要取消标记的坐标(提示以x y的形式输入x代表行,y代表列)n");
		scanf("%d%d", &i, &j);
		if (arr[i - 1][j - 1] == '#')
		{
			printf("取消成功n");
			arr[i - 1][j - 1] = '*';
		}
		else {
			printf("取消标记失败n");
			goto b;
		}
		break;
	default:
		printf("选择错误,请重新选择n");
		goto b;

	}
	system("cls");
	playboard(arr, H, L);
}
int  win(char arr[H][L], int x, int y) {
	int i = 0, j = 0;
	int count = 0;
	for (i = 0; i < x; i++) {
		for (j = 0; j < y; j++) {
			if (arr[i][j] == 'A')
			{
				printf("很遗憾,你输了n");
				return 0;
			}
			else if (arr[i][j] == '*' || arr[i][j] == '#')
				count++;
		}
	}
	if (count > N)
		return 1;
	else
	{
		printf("恭喜你,你赢了n");
		return 0;
	}
}
void clearance(char arr[H][L], char arr1[H][L], int a, int b, int x, int y) {
	int m,n;
	for (m = a ; m <= a+2; m++) {
		for (n = b; n <= b + 2; n++) {
			if (m >= 0 && m < x && n < y && n >= 0) {
				if (arr1[m][n] == '0' && arr[m][n] == '*')
				{
					arr[m][n] = arr1[m][n];
					clearance(arr, arr1, m - 1, n - 1, x, y);

				}
				else if (arr[m][n] != '#')
					arr[m][n] = arr1[m][n];
			}
		}


	}



}
void game() {
	char arr[H][L] = { 0 };
	char arr1[H][L] = { 0 };
	int n;
	printf("扫雷游戏即将开始,敬请期待n");
	board(arr, H, L);
	playboard(arr, H, L);
	n = 1;
	while (n)
	{
		play(arr, arr1, H, L);
		n = win(arr, H, L);
	}
}

最后奉上码云网站C语言代码: 储存一些认真编写的C语言代码 (gitee.com)icon-default.png?t=LBL2https://gitee.com/build-xiaochunbao/c-language-code

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>