C语言 成为排雷高手!(初级版)

一,前言

        扫雷,作为Windows经典小游戏,想必各位铁汁们必定是有尝试过的。那么,有没有铁汁好奇扫雷是如何设计的呢?那么今天就由我来带领各位对C语言如何实现扫雷做一个初步的介绍。

二.正文

        首先,我们既然要使用C语言复刻扫雷,那么我们自然是需要先了解扫雷有哪些基本的特点与功能。

如上图,这是比较经典的扫雷游戏界面(简单版)。

可以看到,扫雷大致有这样几个基本功能。

①.可以通过菜单实现是否选择开始游戏(或者继续游玩与退出游戏)

②.棋盘的大小是9*9的格子。

③.简单版的扫雷需要在9*9=81个格子中随机投放十个“炸弹”。

④.可以排雷(即当该位置不是雷时显示周围的雷,如果是雷需要结束游戏,当雷全部被排查出时返回菜单)。

接下来就可以开始逐步尝试实现各个功能了。

一.主函数

在这里真正的实现通过菜单控制游戏是否重新开始。

int main()
{
	int key = 0;
	srand((unsigned int)time(NULL));//配合函数生成随机数。保证炸弹投放随机。
	do
	{
		door();//制作菜单的函数
		printf("请做出你的选择-->");
		scanf("%d", &key);
		switch (key)//配合菜单函数实现游戏开始,继续与退出的选择
		{
		case 0:
			printf("退出游戏\n");
			break;
		case 1:
			printf("恭喜你成为排雷兵\n");
			game();
			break;
		default:
			printf("输入数据有误,请重新输入\n");
			break;
		}
	} while (key);

	return 0;
}

 二,自定义函数

1.制作并打印菜单的函数

void door()//初始的菜单
{
	printf("*********************\n");
	printf("****** 1.begin ******\n");
	printf("****** 0.exit ******\n");
	printf("*********************\n");
}

因为这里的函数不需要与其他的函数产生交集,不需要返回值,故而定义为空函数。

2.生成棋盘

        在这里通过观察我们可以发现。扫雷的游戏场景是建立在一个9*9的棋盘内的。

        联想到C语言中可以较好的实现这种功能的是什么呢?

                                        数组!

准确的来讲应该是二维的数组。因此我们需要定义二维数组来作为承载我们游戏的基础场景。

那么这样的数组我们需要几个呢?

想一想,在我们游玩扫雷时,除了供我们进行排查的一个棋盘外,当我们游戏通关或者失败时是否需要另个一完整的棋盘来显示炸弹的分布情况呢?

答案是需要的。因此,这样用来承载游戏的棋盘我们需要至少两个。并且一个在游戏结尾时给游玩者查看,另一个则需要在游戏过程中展示给玩家看并且给予玩家操作的机会。

如下图,我们生成了两个数组,用来储存游戏中投放的炸弹与安全区的信息。(ROWS与COLS均为define定义,会在文章末尾放出)。

char mine[ROWS][COLS] = { 0 };//存放放好的雷的信息
char show[ROWS][COLS] = { 0 };//存放排查出的的雷的信息,用于输出。

到此为止我们就拥有了两个“棋盘”。但也只是拥有而已,我们该如何使用它呢?

3.初始化棋盘

        初始化棋盘,类比做初始化变量,就是给棋盘里的空位放置为安全区,或是炸弹。

        因为是要保证炸弹随机投放,自然不可能是我们手动初始化棋盘,那样不但累,且游戏也会变得无聊。

        因此,我们需要定义一个函数来随机初始化棋盘。

如下:

void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
//rows与cols分别为棋盘的行与列
//set是该函数向棋盘内填充的内容,这里使用了字符形。
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;

		}
	}
}

4.布置炸弹。

        完成初始化之后,我们的棋盘就算初步的制作完毕了。但是此时游戏还不能开始。

        为啥呢?因为此时的棋盘内仅靠这一个函数填充进去的内容只有“安全区”,而没有炸弹。这样的扫雷实在是没得玩,因为无论如何都不会失败。那么就需要用到我们的下一个函数了。

如下

void Setmine(char board[ROWS][COLS], int row, int col)
{
	int count = Easy_count;
	while (count)
	{
		int x = rand() % row + 1;//使用rand函数利用种子生成随机的坐标
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] ='1';//这里我用‘0’表示安全,用‘1’表示炸弹
			count--;        //这里之所以用字符1和0而不用别的后面会提到。
		}
	}
}

好了,在这个函数之后,我们的游戏棋盘就已经基本完成了。至少棋盘是可以使用了。那么接下来就要完成扫雷这个游戏最最重要也是最最刺激的核心玩法了——排查雷

5.排查炸弹。

代码如下

void 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("请输入坐标\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//限定棋盘大小(棋盘大小与数组大小并不相同)
		{
			if (mine[x][y]=='1')//当所输入坐标对应为字符1时,触发炸弹,结束游戏
			{
				printf("很遗憾,你牺牲了\n");
				DisplayBoard(mine, ROW, COL);//打印出真实的棋盘
				break;
			}
			else
			{
				if (show[x][y] != '*')//防止反复排查同一坐标。
				{
					printf("坐标已安全,无需再次排查\n");
				}
				else
				{
					//统计安全坐标周围8个坐标中的雷
					int count = Getmine_count(mine, x, y);
					show[x][y] = count + '0';//利用ASCII码做转换,后面会简单介绍。
					DisplayBoard(show, ROW, COL);//实时打印出棋盘
					win++;
				}
			}
		}
		else
		{
			printf("输入坐标不合法,重新输入\n");
		}
	}
	if (win == row * col - Easy_count)
	{
		printf("恭喜你功成身退!\n");
		DisplayBoard(mine, ROW, COL); 
	}
}

        在这个函数中,细心地铁汁萌也许会发现,我这里使用的棋盘大小与数组的大小并不相同,数组空出了一部分。

        这实际上是为了防止在统计安全区周围炸弹的个数时(也就是代码中我还没有提到的Getmine_count函数),数组读取越界。

6.实现显示安全区周围的炸弹个数。

代码如下:

int Getmine_count(char mine[ROWS][COLS],int x,int y)
{
	return 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] +
		mine[x - 1][y]-8*'0';
}

函数中的运算实际上是为了将数组中的字符利用ASSCII码转换为数字。如‘0’的十进制ASCII码为48,‘1’的十进制ASCII码为49等等。这也是前面使用字符1和0作为炸弹与安全区表示的原因。

好了,到此为止。C语言实现扫雷的基本代码已经介绍完毕。

接下来是见证奇迹的时刻

三,完整的程序

1.text.c

#include<stdio.h>
#include"game.h"
void game()//完成游戏的过程
{
	char mine[ROWS][COLS] = { 0 };//存放放好的雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的的雷的信息,用于输出。
	//初始化棋盘
	InitBoard(mine,ROWS, COLS,'0');
	InitBoard(show, ROWS, COLS,'*');
	//布置雷
	Setmine(mine,ROW,COL); 
	//排查雷
	Findmine(mine, show, ROW, COL);
}

void door()//初始的菜单
{
	printf("*********************\n");
	printf("****** 1.begin ******\n");
	printf("****** 0.exit ******\n");
	printf("*********************\n");
}

int main()
{
	int key = 0;
	srand((unsigned int)time(NULL));
	do
	{
		door();
		printf("请做出你的选择-->");
		scanf("%d", &key);
		switch (key)
		{
		case 0:
			printf("退出游戏\n");
			break;
		case 1:
			printf("恭喜你成为排雷兵\n");
			game();
			break;
		default:
			printf("输入数据有误,请重新输入\n");
			break;
		}
	} while (key);

	return 0;
}

2.game.h

#pragma once

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define Easy_count 10
#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 set);
void DisplayBoard(char board[ROWS][COLS],int row, int col);
//放置雷
void Setmine(char board[ROWS][COLS], int row, int col);

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

3.game.c

#include"game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;

		}
	}
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("——————排雷炮灰——————\n");
	//打印列
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		//打印行
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
//放置雷
void 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 Getmine_count(char mine[ROWS][COLS],int x,int y)
{
	return 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] +
		mine[x - 1][y]-8*'0';
}
//排查雷
void 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("请输入坐标\n");
		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
			{
				if (show[x][y] != '*')
				{
					printf("坐标已安全,无需再次排查\n");
				}
				else
				{
					//统计安全坐标周围8个坐标中的雷
					int count = Getmine_count(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
		}
		else
		{
			printf("输入坐标不合法,重新输入\n");
		}
	}
	if (win == row * col - Easy_count)
	{
		printf("恭喜你功成身退!\n");
		DisplayBoard(mine, ROW, COL); 
	}
}

三.总结 

以上,是本次对C语言实现扫雷部分基本功能的简单介绍。除此之外扫雷还有大量进阶的操作功能如:选择难度,若所选区域不是炸弹则展开一片,加入扫雷时间记录,以及让玩家可以标记炸弹位置等,等待你去实现。

  • 30
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值