扫雷游戏(保姆式教程)

前言说到扫雷游戏,小时候玩着可头疼了,玩的时候就乱点,也不知道啥意思,完全凭感觉,至今回想还挺有意思,今天带着大家小小实现一波简易版扫雷游戏。代码分为三个部分,game.h是存放声明的部分,game.c是游戏具体实现的部分,test.c是我们大概逻辑部分。

目录

❤️总体思路:

🤞1.打印菜单栏

🤞2.数组的定义

🤞3.数组的初始化

🤞4.打印数组

🤞5.布置雷

🤞6.排查雷

🤞7.game.h代码部分

🤞8.game.c代码部分

🤞9.test.c代码部分


 

 

总体思路:

扫雷游戏是在一堆格子里去排查,格子的话我们可以定义成二维数组的形式,其中这些格子包括雷,和含有多少雷的信息。如下图第一张所示,左上角就是我含有雷的个数,第二张图片上数字部分是它的周围含有几个雷。

既然有存放雷,和显示雷的信息,不如我们就定义两个数组,一个是存放雷,一个存放含雷的信息,并且这两个数组的大小是一样,为了保证位置一一对应关系,这样一来方便了改坐标的代码。我们知道当我们选择棋盘周围的坐标时,去统计周围雷信息的时候就会造成数组访问越界,所以不如我们定义的数组的时候,就多定义两行两列(左右都要所以定义两列,行是一样的道理,上下部分),但是显示的时候不能出现多出来的两行和两列。两个数组定义完就是初始化,和打印,打印完了,我们在布置雷,布置好雷就开始排雷。总体思路是这样接下来我们在去细化。


1.打印菜单栏

玩游戏都有个菜单栏,菜单栏里有选项,玩游戏或者不玩游戏,我们就来定义玩游戏选输入 1, 不玩游戏,我们输入0。接下来就写一个简易的菜单栏

// test.c 代码部分


void menu()
{
	printf("************************\n");
	printf("******** 1.play ********\n");   //玩游戏
	printf("******** 0.exit ********\n");   //退出游戏
	printf("************************\n");

}

菜单栏有了,接下来就是调用这个菜单栏,我们都知道玩游戏我们可以多次玩,并不是只玩以此,所以菜单栏打印的话也要放在循环里,并且一上来就有一个菜单栏,所以用到do....while循环。

补充:do......while循环就是先做一次事,再循环。

调用菜单栏如下:

// test.c 代码部分

int main()
{

	do
	{

		menu();  //调用菜单栏
		
	} while ();
}

调用完菜单栏,接下来就是我们去选择,选择你给输入一个数吧,所以定义一个变量,来作为输入部分,代码如下:

// test.c 代码部分

int main()
{
	int input = 0;
	
	do
	{

		menu();
		printf("请选择:>");
		scanf("%d", &input);

	} while (input);
}

输入完之后,你肯定要接收进来,接受的结果来判断我们是否玩游戏,所以我们选择switch...case语句,代码如下:

// test.c 代码部分

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,刚好就退出循环,如果是非0,则一直循环
                      //因此用input来判断循环是否进行
}


 

2.数组的定义

 接下来才是游戏代码,上面说到我们要定义两个数组,一个存放雷的数组,一个存放雷的信息数组,我们就先来个9*9的数组,定义数组行和列不如用宏来定义,因为方便我们改棋盘大小,代码如下:

// game.h 代码部分

#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
// test.c 代码部分

void game()
{
	char mine[ROWS][COLS] = { 0 };  //存储雷

	char show[ROWS][COLS] = { 0 };  //存储雷的信息

}

3.数组的初始化

我们将雷的数组初始化为字符0,将存放雷信息的部分初始化为字符1,既然初始化为不同的字符,所以函数传参的时候我们就将对应的字符传过去就行。初始化是将数组全部内容初始化,所以传数组行和列的时候是对应的总行和总列。代码如下:

// test.c 代码部分

void game()
{
	char mine[ROWS][COLS] = { 0 };  //存储雷
	char show[ROWS][COLS] = { 0 };  //存储雷的信息

	//初始化
	InitBoard(mine, ROWS, COLS, '0');

	InitBoard(show, ROWS, COLS, '*');

}
// game.h 代码部分

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

//初始化
InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
// game.c 代码部分

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


 

4.打印数组

前面说了由于怕数组越界访问,因此我们多加了两行两列,但是实际打印的时候我们让玩家并不能看到多出的两行两列,所以数组的行和列传的时候不是总行和总列,我们打印的行和列是从1~9,列也是从1~9,代码如下:

// test.c 代码部分

void game()
{
	char mine[ROWS][COLS] = { 0 };  //存储雷
	char show[ROWS][COLS] = { 0 };  //存储雷的信息

	//初始化
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印格子
	DisplayBoard(show, ROW, COL); //我们不需要将存放雷的位置打印,所以只打印雷的信息

}
// game.h 代码部分

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

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

//打印格子
DisplayBoard(char board[ROWS][COLS], int row, int col);
// game.c 代码部分

DisplayBoard(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");
	}
}

效果图如下:

我们可以看到 上面的图片并不能一眼的看出对应的位置,所以我们给行和列加上序号的话这样就方便多了。代码和效果图如下:

// game.c 代码部分

DisplayBoard(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");
	}
}

 

 


 5.布置雷

雷的布置实在mine数组里布置,随机生成一个坐标布置,既然说到随机数的生成,已经在猜数字小游戏里说过了,这里我就不再过多描述。代码如下:(大家要是测试的时候可以布置后将mine数组打印看看是不是随机)

补充:猜数字游戏https://blog.csdn.net/m0_64221480/article/details/124230089?spm=1001.2014.3001.5501

代码如下:

// test.c 代码部分

void game()
{
	char mine[ROWS][COLS] = { 0 };  //存储雷
	char show[ROWS][COLS] = { 0 };  //存储雷的信息

	//初始化
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印格子
	DisplayBoard(show, ROW, COL);

	//布置雷
	SetMine(mine, ROW, COL);
	//DisplayBoard(mine, ROW, COL);  看看是不是随机生成


}
// game.h 代码部分

#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define EASY_COUNT 10   //设置雷的个数

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

//打印格子
DisplayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
SetMine(char board[ROWS][COLS], int row, int col);
// game.c 代码部分

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] == '0')
			{
				board[x][y] = '1';
				count--;
			}
	}
}

 


 

6.排查雷

玩家要排查雷的话,玩家首先要输入一个排查雷的坐标,如果玩家输入的坐标,不在我们的数组范围内那就提示一个非法坐标,并让他重新输入,如果在数组范围内的话,我们还要考虑玩家输入的坐标是否是输入过的,输入过的也要提示一下,以上排除完,玩家输入坐标位置万一有雷的话,直接就输掉游戏,如果没雷才去统计周围的雷的个数并且打印出来。代码如下:

// test.c 代码部分

void game()
{
	char mine[ROWS][COLS] = { 0 };  //存储雷
	char show[ROWS][COLS] = { 0 };  //存储雷的信息

	//初始化
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印格子
	DisplayBoard(show, ROW, COL);

	//布置雷
	SetMine(mine, ROW, COL);
	//DisplayBoard(mine, ROW, COL);

	//排查雷
	FindMine(mine, show, ROW, COL);

}
// game.h 代码部分

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

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

//打印格子
DisplayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
SetMine(char board[ROWS][COLS], int row, int col);

//排查雷
FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

 

// game.c 代码部分

FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请玩家输入坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已被排查过,请勿重复排查\n");
			}
			else
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);  //调用函数去统计周围雷的个数
					show[x][y] = count + '0';
					DisplayBoard(show, row, col);
					
				}
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

统计周围雷的函数,我们知道当周围雷统计的时候是统计的是字符,而让他返回时返回的时数字,我们知道字符0的ASIIC码是48,而字符1的ASIIC码是49。字符1= ASIIC(‘1’) - ASIIC(‘0’),进行转换得来,所以我们每一个减去字符0就能得到,所以如下图和代码:

 

// game.c 代码部分

//计算坐标周围雷的个数
int get_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';
}

以上在代码在排雷得过程我们会发现排雷代码并没有结束的条件,我们知道我们的格子有81个,而雷有10,也就是玩家在排除了71次就会终止游戏并提示游戏结束,玩家获胜,所以我们来看看下面修改后的代码:

// game.c 代码部分

FindMine(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("请玩家输入坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已被排查过,请勿重复排查\n");
			}
			else
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					break;
				}
				else
				{
					win++;
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, row, col);
					
				}
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
	}
}

以上就是游戏的思路过程。下面我将把game.h , game.c,test.c 的代码分别列出


7.game.h代码部分

#define _CRT_SECURE_NO_WARNINGS
#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

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

//打印格子
DisplayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
SetMine(char board[ROWS][COLS], int row, int col);

//排查雷
FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

 

 


 8.game.c代码部分

#include "game.h"

//实现初始化
InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

//打印格子
DisplayBoard(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");
	}
}

//布置雷
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] == '0')
			{
				board[x][y] = '1';
				count--;
			}
	}
}

//计算坐标周围雷的个数
int get_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';
}

//排查雷
FindMine(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("请玩家输入坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已被排查过,请勿重复排查\n");
			}
			else
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					break;
				}
				else
				{
					win++;
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, row, col);
					
				}
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
	}
}

 

 


9.test.c代码部分

#include "game.h"
void menu()
{
	printf("************************\n");
	printf("******** 1.play ********\n");
	printf("******** 0.exit ********\n");
	printf("************************\n");

}

void game()
{
	char mine[ROWS][COLS] = { 0 };  //存储雷
	char show[ROWS][COLS] = { 0 };  //存储雷的信息

	//初始化
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印格子
	DisplayBoard(show, ROW, COL);

	//布置雷
	SetMine(mine, ROW, COL);
	//DisplayBoard(mine, ROW, COL);

	//排查雷
	FindMine(mine, show, ROW, COL);

}

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值