从零到一快速学会扫雷

目录

  • 前言
    • 一、游戏分析
    • 二、游戏的实现
      • 1、菜单
      • 2、主函数
      • 3、game函数的实现
        • 3.1、创建数组并初始化
        • 3.2、打印棋盘
        • 3.3、布置雷
        • 3.4、排雷
      • 4、游戏具体代码
        • 4.1、game.h
        • 4.2、test.c
        • 4.3、game.c
  • 最后

前言

扫雷这个游戏想必大家都不陌生吧,规则我就不多说了,我们今天就来用C语言来简单实现它。

一、游戏分析

从零到一快速学会扫雷_第1张图片
游戏左上角的数字是雷的数量,上图显示的数字是数字周围一圈含雷的个数,由图我们可以创建一个 9*9 的数组来模拟方格,如果我选择最外的一圈的格子,那么周围格子就没有一圈了,怎么办呢?

从零到一快速学会扫雷_第2张图片
就像上图,2周围只有3个格子,怎么样才能让它周围也有8个格子呢?
我们可以多加2行、2列,这样图中每个格子周围都有8个格子,好判断。
那我们就创建一个11*11的数组。用1表示雷,0表示非雷。
问题又来了,如果格子周围只有一个雷,那它把1存进去显示1,那判断的时候岂不是变成雷了,那我们可以再创建一个数组,专门存放显示的数字。

1、创建2个数组,一个数组(a)用来存放布置好的雷的信息,另一个数组(b)存放排查出的雷的信息。
2、a 数组初始化为 ’ 0 ’ ,布置雷的时候改为 ’ 1 ’ 。
3、b 数组初始化为 ’ * ’ ,排除雷后,具体位置改为数字字符,如 ’ 3 ’ 。

二、游戏的实现

1、菜单

void menu()
{
	printf("*****************************\n"); 
	printf("*******    1.play    ********\n"); 
	printf("*******    0.exit    ********\n");
	printf("*****************************\n");
}

2、主函数

首先,我们思考一下,本次游戏应该最少执行一次,在执行过程中进行选择,那么我们应该使用 do while 循环来实现。根据选择不同,来执行相应的程序,那么应该使用 switch 语句。
下面我们来看代码:

int main()
{
	int input = 0;
	do
	{
		menu();                        //每次在选择前打印菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();                    //开始游戏
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择!\n");
			break;
		}
	} while (input);                //根据输入的值来确定是否进行循环,0则退出循环
	return 0;                       //这也是为什么在菜单中把退出游戏设置成0的原因
}

3、game函数的实现

3.1、创建数组并初始化

#define M 11
#define N 11
void game()
{
	//设计两个数组存放信息
	char a[M][N] = { 0 };
	char b[M][N] = { 0 };
	// 初识化棋盘   
	// a数组初始化为'0'
	// b数组初始化为'*'
	chu_shi(a, M, N, '0');   //将 0 和 * 传过去方便初始化
	chu_shi(b, M, N, '*');
}
void chu_shi(char p[M][N], int m, int n, char w)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < m; i++)
		for (j = 0; j < n; j++)
			p[i][j] = w;
}

3.2、打印棋盘

void game()
{
	//设计两个数组存放信息
	char a[M][N] = { 0 };
	char b[M][N] = { 0 };
	//初识化棋盘   
	// a数组初始化为'0'
	// b数组初始化为'*'
	chu_shi(a, M, N, '0');
	chu_shi(b, M, N, '*');
	//打印棋盘
	da_yin(a, M - 2, N - 2);      //M-2,N-2就是9,因为我们的游戏是9*9的,所以传9过去,方便打印
	da_yin(b, M - 2, N - 2);
}
void da_yin(char p[M][N], int m, int n)
{
	int i = 0;
	int j = 0;
	for (j = 0; j <= n; j++)    //打印列号
		printf("%d ", j);
	printf("\n");
	for (i = 1; i <= m; i++)
	{
		printf("%d ", i);      //打印行号
		for (j = 1; j <= n; j++)
			printf("%c ", p[i][j]);     //注意:数组p是char型,用%c打印每个元素
		printf("\n");
	}
}

结果:
从零到一快速学会扫雷_第3张图片
打印结果能够一目了然,哪个元素是几行几列,我们棋盘打印已经完成下一步就是布置雷了。

3.3、布置雷

我们要布置10个雷在数组 a 里,怎么样才能做到随机生成呢?
我们可以生成随机数,来达到效果。
随机数的生成:

#include
#include
#include
int main()
{
	srand((unsigned int)time(NULL));    //设置一个随机数的生成器	
	int m = rand()%9//因为 rand 生成随机数范围0~32767
	printf("%d",m);                   //所以 %9 使随机数生成范围为0~8
}
#include
#include
#include
srand((unsigned int)time(NULL));     //我们需要放在 main 函数中
void game()
{
	char a[M][N] = { 0 };
	char b[M][N] = { 0 };
	chu_shi(a, M, N, '0');
	chu_shi(b, M, N, '*');
	//布置雷
	bu_lei(a, M - 2, N - 2);
	da_yin(a, M - 2, N - 2);
}
void bu_lei(char p[M][N], int m, int n)
{
	int c = 10;
	while (c)
	{
		int x = rand() % m + 1;
		int y = rand() % n + 1;
		if (p[x][y] == '0')      //避免雷的重复
		{
			p[x][y] = '1';
			c--;
		}
	}
}

输出:
从零到一快速学会扫雷_第4张图片
我们可以观察到10个雷已经布置成功,接下来就是排雷了。

3.4、排雷

首先,我们排雷是一步一步排的,这样我们就需要一个while循环来首先,我们输入一个行和列都是1到9的坐标,然后显示出这个坐标旁边8个格子的雷的个数,这样我们便可以写出如下代码:

int ji_shu(char a[M][N], int x, int y)
{
	return (a[x - 1][y] +
		    a[x - 1][y - 1] +
		    a[x][y - 1] +
		    a[x + 1][y - 1] +
		    a[x + 1][y] +
		    a[x + 1][y + 1] +
		    a[x][y + 1] +
		    a[x - 1][y + 1] - 8 * '0');     
}             //每个数字字符减去一个‘0’即可得到相应数字
void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			int k = ji_shu(a, x, y);   //计算旁边8个格子的雷的个数
			b[x][y] = k + '0';         //因为字符0的ASCII码值为48,加上对应数字0到9就能得到对应的数字字符
			da_yin(b, M - 2, N - 2);   //每次输入完后打印棋盘b
		}
		else
			printf("坐标非法,请重新输入:>\n");
	}
}

从零到一快速学会扫雷_第5张图片
如果排到雷了,我们应该让游戏结束,添加一个if 语句即可:

void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (a[x][y] == '1')    //排到雷了
			{
				printf("你被炸死了\n");
				da_yin(a, M - 2, N - 2);  //让你看看雷的位置
				break;                   //退出 while 循环
			}
			else
			{
				int k = ji_shu(a, x, y);
				b[x][y] = k + '0';
				da_yin(b, M - 2, N - 2);
			}
		}
		else
			printf("坐标非法,请重新输入:>\n");
	}
}

如果排完了,那我们应该要退出呀,我们应该控制 while 循环来退出来:

void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<(M-2)*(N-2)-10)      //排完71个格子退出循环
	{
		printf("请输入坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (a[x][y] == '1')
			{
				printf("你被炸死了\n");
				da_yin(a, M - 2, N - 2);
				break;
			}
			else
			{
				int k = ji_shu(a, x, y);
				b[x][y] = k + '0';
				da_yin(b, M - 2, N - 2);
				win++;
			}
		}
		else
			printf("坐标非法,请重新输入:>\n");
	}
	if (win == (M - 2) * (N - 2) - 10)
	{
		printf("恭喜你,排雷成功\n");
		da_yin(a, M-2, N-2);
	}
}

我们这个代码还是不够完善,当我们输入2 2后再输入2 2,它还是会输出,我们应该用 if 语句限制一下:

void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<(M-2)*(N-2)-10)
	{
		printf("请输入坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (b[x][y] == '*')      //防止重复排查
			{
				if (a[x][y] == '1')
				{
					printf("你被炸死了\n");
					da_yin(a, M - 2, N - 2);
					break;
				}
				else
				{
					int k = ji_shu(a, x, y);
					b[x][y] = k + '0';
					da_yin(b, M - 2, N - 2);
					win++;
				}
			}
			else
				printf("该坐标已经被排查过了\n");
		}
		else
			printf("坐标非法,请重新输入:>\n");
	}
	if (win == (M - 2) * (N - 2) - 10)
	{
		printf("恭喜你,排雷成功\n");
		da_yin(a, M-2, N-2);
	}
}

好了,我们游戏具体解析已经完成了,接下来就是游戏封装了。

4、游戏具体代码

test.c:扫雷游戏的测试逻辑
game.h:游戏函数的声明
game.c :游戏函数的实现

4.1、game.h

#pragma once
#include
#include 
#include 

#define M 11
#define N 11
//初始化棋盘
void chu_shi(char p[M][N], int m, int n, char w);
//打印棋盘
void da_yin(char p[M][N], int m, int n);
//布置雷
void bu_lei(char p[M][N], int m, int n);
//排雷
void pai_lei(char a[M][N], char b[M][N], int m, int n);

4.2、test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************\n");
	printf("*******    1.play    ********\n");
	printf("*******    0.exit    ********\n");
	printf("*****************************\n");
}
void game()
{
	char a[M][N] = { 0 };
	char b[M][N] = { 0 };
	chu_shi(a, M, N, '0');
	chu_shi(b, M, N, '*');
	bu_lei(a, M - 2, N - 2);
	pai_lei(a, b, M - 2, N - 2);
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

4.3、game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

void chu_shi(char p[M][N], int m, int n, char w)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < m; i++)
		for (j = 0; j < n; j++)
			p[i][j] = w;
}
void da_yin(char p[M][N], int m, int n)
{
	int i = 0;
	int j = 0;
	for (j = 0; j <= n; j++)
		printf("%d ", j);
	printf("\n");
	for (i = 1; i <= m; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= n; j++)
			printf("%c ", p[i][j]);
		printf("\n");
	}
}
void bu_lei(char p[M][N], int m, int n)
{
	int c = 10;
	while (c)
	{
		int x = rand() % m + 1;
		int y = rand() % n + 1;
		if (p[x][y] == '0')
		{
			p[x][y] = '1';
			c--;
		}
	}
}
int ji_shu(char a[M][N], int x, int y)
{
	return (a[x - 1][y] +
		    a[x - 1][y - 1] +
		    a[x][y - 1] +
		    a[x + 1][y - 1] +
		    a[x + 1][y] +
		    a[x + 1][y + 1] +
		    a[x][y + 1] +
		    a[x - 1][y + 1] - 8 * '0');
}

void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<(M-2)*(N-2)-10)
	{
		printf("请输入坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (b[x][y] == '*')
			{
				if (a[x][y] == '1')
				{
					printf("你被炸死了\n");
					da_yin(a, M - 2, N - 2);
					break;
				}
				else
				{
					int k = ji_shu(a, x, y);
					b[x][y] = k + '0';
					da_yin(b, M - 2, N - 2);
					win++;
				}
			}
			else
				printf("该坐标已经被排查过了\n");
		}
		else
			printf("坐标非法,请重新输入:>\n");
	}
	if (win == (M - 2) * (N - 2) - 10)
	{
		printf("恭喜你,排雷成功\n");
		da_yin(a, M-2, N-2);
	}
}

最后

跟三子棋一样,都是代码一大堆,看得令人头疼,其实不然,只要我们把它细分下来,就会发现其实都挺简单的,都是我们学过的,只是见的少罢了,这就要求我们多做练习提高见识,这样才能写出好代码。
扫雷游戏也就圆满完成了,希望大家都能有所收获,有所成长。
下期见啦~

你可能感兴趣的:(记录学习,c语言)