简单上手学会基本的扫雷游戏代码实现



扫雷游戏的基本实现实际上还是比较简单的,没有用到很深的知识,只需要我们理解和掌握数组和函数的使用。
接下来开始带大家慢慢来用c语言来实现扫雷游戏的运行代码。

1.扫雷游戏的分析

1.1扫雷游戏的功能

•用控制台实现
•菜单界面,玩家选择进入游戏或者退出游戏
•游戏界面,玩家开始一步步的扫雷

在扫雷游戏过程中,我们要实现扫雷棋盘的大小,棋盘中雷的个数,以及当玩家扫过的位置不是雷的时候,周围一圈雷的信息

2.扫雷游戏的代码实现分析过程

2.1游戏菜单界面

首先我们可以设置游戏的界面,界面的设置也十分的简单,为了使我们的思路更加清晰,我们可以用一个函数来实现。

代码如下:(按照自己喜欢的来就行)

#include <stdio.h>
void menu()				//menu函数,向玩家展示游戏界面
{
	printf("********************\n");
	printf("*****  1.play  *****\n");
	printf("*****  0.exit  *****\n");
	printf("********************\n");
}

int main()
{
	menu();
	return 0;
}

2.2玩家的选择

接着实现玩家的输入,玩家首先要看到菜单界面,并且因为玩家可能想再次玩游戏或者输入错误,所以我们可以用do while循环来实现多次输入,用switch语句来实现玩家的不同选择。

代码如下:(代码无法运行,因为play函数(扫雷游戏实现)的代码我们还没有写)

#define _CRT_SECURE_NO_WARNINGS				//防止scanf报错

#include <stdio.h>

int main()
{
	int input = 0;	//do while循环执行一次后要while判断是否再次进入循环,所以input要在循环外面定义
	do
	{
		printf("请输入你的选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			play();				//进入扫雷游戏
			break;
		case 0:
			printf("exit\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
		}
	} while (input);
	return 0;
}

2.3扫雷游戏界面

以9* 9的棋盘为例,我们要在棋盘上布置雷和排查雷,很容易想到用二维数组来存放这些信息。
布置雷的位置存放1,其余位置存放0。
在这里插入图片描述
但是我们玩过扫雷的都知道,当我们排查雷的时候,如果当前位置没有雷,则该位置会统计显示周围1圈8个位置雷的总数,当我们排查最外圈的雷的时候,周围一圈可能会发生越界的情况,所以我们可以在创建数组时候,给数组扩大一圈,周围一圈全都不布置雷,即可解决越界的问题,所以我们在创建时可以创建11* 11的数组棋盘。

在这里插入图片描述
在创建完数组后,我们会发现布置雷显示的1(红色部分的1)可能会和统计雷个数的1(图中周围8个都为黄色的格子)信息重合,数组太杂乱,这样不方便我们调整和观察,有的人肯定会想,那为什么埋雷的时候用0/1表示,不用其他的符号来表示呢,但是如果真的将埋雷的信息和统计雷个数的信息放在1个数组里面不利于我们思考和实现,很可能代码写着写着弄混淆了,也可能代码写完后十分的复杂也不利于我们修改,所以我们可以用两个数组来实现,1个数组用来存放埋雷的信息,0表示该处没有雷,1表示该处有雷,用另外一个数组用来存放统计周围雷的个数的信息,将数组全部用表示。
在这里插入图片描述
为了后面能够将两个数组用同一个函数解决,我们可以将它们的元素统一成字符(因为
是字符,0和1可以转变为字符)。
为了使我们能够方便的改变棋盘的大小,我们可以将行和列都宏定义一个常量,这样之后我们想要改变棋盘的大小,只需要改宏定义的值即可。

代码如下:

#define ROW 9					//宏定义行为9
#define COL 9					//列为9
#define ROWS ROW+2				//将行和列扩大一圈,行和列都要加2
#define COLS COL+2

void play()
{
	char mine[ROWS][COLS];			//布置好的雷的信息
	char show[ROWS][COLS];			//排查处的雷的信息
}

接下来就要开始实现扫雷过程。

思路:
(1)初始化棋盘。可以用InitBoard函数实现。
(2)打印埋雷信息的棋盘,向玩家展示。可以用DisplayBoard函数实现。
(3)向棋盘中布置一定数量的雷。可以用SetMine函数实现。
(4)玩家开始排查雷。可以用FindMine函数实现。

(1)初始化棋盘
初始化二维数组,可以用双循环来实现,把行和列作为实参传给函数,因为我们想把两个数字的初始化用一个函数来实现,但是两个数组的初始化的内容不同,所以我们可以定义一个变量set,把我们想要初始化的内容作为实参传递给set来实现。

代码如下:

#include <stdio.h>

#define ROW 9					//宏定义行为9
#define COL 9					//列为9
#define ROWS ROW+2				//将行和列扩大一圈,行和列都要加2
#define COLS COL+2

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

void play()
{
	char mine[ROWS][COLS];			//布置好的雷的信息
	char show[ROWS][COLS];			//排查处的雷的信息
	InitBoard(mine,ROWS,COLS,'0');							//(1)初始化棋盘。
	InitBoard(show, ROWS, COLS, '*');
}

(2)打印布置雷信息的棋盘
和初始化棋盘类似,可以在在第0行和第一列加对应的数字表示对应的行,方便玩家输入坐标。

代码如下:

#include <stdio.h>

#define ROW 9					//宏定义行为9
#define COL 9					//列为9
#define ROWS ROW+2				//将行和列扩大一圈,行和列都要加2
#define COLS COL+2

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i, j;
	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 play()
{
	char mine[ROWS][COLS];			//布置好的雷的信息
	char show[ROWS][COLS];			//排查处的雷的信息
	DisplayBoard(show,ROW,COL);							//(2)打印埋雷信息的棋盘
}

结果如图:
在这里插入图片描述

(3)向棋盘中布置一定数量的雷
因为每次要在不同位置随机生成雷,所以我们需要用到rand函数来提供随机数,在主函数中添加srand((unsigned int)time(NULL));
并声明头文件:
#include <stdlib.h>
#include <time.h>
(原因在猜数字游戏中有详细的解释)

我们可以将雷的个数设定成一个可以改变的常量,用MineNumber实现,方便我们之后更改,每次随机的位置如果不是雷,就布置雷,并且把需要布置雷的次数减1,一直重复操作,直至雷全部布置完,用循环实现布置雷。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 9					//宏定义行为9
#define COL 9					//列为9
#define ROWS ROW+2				//将行和列扩大一圈,行和列都要加2
#define COLS COL+2
#define MineNumber 10			//定义需要设置雷的个数,方便更改

void SetMine(char mine[ROWS][COLS],int row,int col)
{
	int count = MineNumber;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;		//每次进入循环,生成不同的随机数,控制生成数的范围在棋盘内
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';			//如果x,y处不是雷,那么就在此处设置雷
			count--;
		}
	}
}

void play()
{
	char mine[ROWS][COLS];			//布置好的雷的信息
	char show[ROWS][COLS];			//排查处的雷的信息
	SetMine(mine, ROW, COL);								//(3)向棋盘中布置一定数量的雷。
}

(4)玩家开始排查雷
首先需要玩家输入排雷的坐标x和y,然后进行判断,如果该处是雷,游戏就失败了,如果不是雷,就要向玩家反馈x,y处周围雷的总数,可以用 GetMineCount函数实现。
周围一圈雷的坐标如下:

在这里插入图片描述
代码如下:

#include <stdio.h>

#define ROW 9					//宏定义行为9
#define COL 9					//列为9
#define ROWS ROW+2				//将行和列扩大一圈,行和列都要加2
#define COLS COL+2
#define MineNumber 10

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return (mine[x - 1][y - 1] +
		mine[x - 1][y] +
		mine[x - 1][y + 1] +
		mine[x][y - 1] +
		mine[x][y + 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] - 8 * '0');
//因为创建的是字符数组,我们要得到雷的个数需要转换,字符减去字符0即可得到对应的数字,周围8个字符总共需减去8个字符0
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;
	int total = 0;					//玩家排雷的次数
	while (total < row * col - MineNumber)
	{
		printf("请输入需要排查的位置:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)		//玩家输入的位置需在棋盘内
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				DisplayBoard(mine, ROW, COL);			//玩家失败后,向玩家展示所有雷布置的位置
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);		//此处我们需要设计函数,来返回玩家查找的位置周围一圈有多少雷
				show[x][y] = count + '0';				//函数返回的是整形,但是我们创建的是字符数组,所以要把整形转变为字符,再替代当前x,y位置的值
				DisplayBoard(show, ROW, COL);
				total++;
			}
		}
		else
		{
			printf("输入错误,请重新输入!\n");
		}
	}
	if (total == row * col - MineNumber)
	{
		printf("恭喜你,挑战成功!");
	}
}

void play()
{
	char mine[ROWS][COLS] = { 0 };			//布置好的雷的信息
	char show[ROWS][COLS] = { 0 };			//排查处的雷的信息
	FindMine(mine, show, ROW, COL);								//(4)玩家开始排查雷
}

3.基本扫雷游戏的完整代码及拓展

稍微调整一下后完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 9				
#define COL 9				

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

#define MineNumber 10			

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

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i, j;
	printf("\n");
	printf("******扫雷游戏******\n");
	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");
	}
	printf("******扫雷游戏******\n");
	printf("\n");
}

void SetMine(char mine[ROWS][COLS],int row,int col)
{
	int count = MineNumber;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;		
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';			
			count--;
		}
	}
}

int GetMineCount(char mine[ROWS][COLS],int x,int y)
{
	return (mine[x - 1][y - 1] +
		mine[x - 1][y] +
		mine[x - 1][y + 1] +
		mine[x][y - 1] +
		mine[x][y + 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] - 8 * '0');
}

void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col)
{
	int x, y;
	int total = 0;				
	while (total < row * col-MineNumber)
	{
		printf("请输入需要排查的位置:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)				
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				DisplayBoard(mine, ROW, COL);			
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);		
				show[x][y] = count + '0';					
				DisplayBoard(show, ROW, COL);				
				total++;
			}
		}
		else
		{
			printf("输入错误,请重新输入!\n");
		}
	}
	if (total == row * col - MineNumber)				
	{
		printf("恭喜你,挑战成功!");
	}
}

void play()
{
	char mine[ROWS][COLS];			
	char show[ROWS][COLS];			
	printf("开始游戏\n");
	InitBoard(mine,ROWS,COLS,'0');							
	InitBoard(show,ROWS,COLS,'*');
	DisplayBoard(show,ROW,COL);								
	SetMine(mine,ROW,COL);									
	FindMine(mine,show,ROW,COL);							
}

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

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;	
	do
	{
		menu();
		printf("请输入你的选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			play();			
			break;
		case 0:
			printf("exit\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
		}
	} while (input);
	return 0;
}

可以发现,当代码数量越来越多时,把代码全部放在一个文件里不利于我们思考,所以我们可以设计多个文件,用多⽂件的形式对函数的声明和定义。

我们实践⼀下,设计三个⽂件:
test.c //文件中写游戏的测试逻辑
game.c //文件中写游戏中函数的实现等
game.h //文件中写游戏需要的数据类型和函数声明等

如图所示:
test.c文件和game.c文件需要用到声明可以用#include "game.h"来调用。
在这里插入图片描述
在这里插入图片描述
当然,我们还可以拓展更多的内容,例如实际上我们玩的扫雷,如果排查的位置不是雷,周围一圈也没有雷,就可以展开一大片,可以标记我们认为是雷的位置,还有排雷的时间显示,需要用到后面的学习知识,这里就不一一介绍了,希望能帮助大家更好的了解最基本的扫雷游戏的原理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值