C语言扫雷游戏及代码实现

说到扫雷游戏我们大家都不陌生,但对于我来说实现起来还是有一定难度的,在这里我想向大家分享一下我是如何通过学习来实现这个游戏的。

一.简单介绍扫雷游戏

        扫雷游戏最初是从“Rlogic”演变过来的。“Rlogic”中,玩家为美国海军陆战队,若路被封死则算输,后来有人在此基础上设计“地雷”游戏,在后来有微软的工程师等参与,使得扫雷游戏风靡全球。

        扫雷游戏有初级10个雷9*9方格,中级40个雷16*16方格,高级99个雷16*30方格,若玩家能避开所有的雷,翻开安全的地板,即为胜利,否则失败。

二.实现扫雷游戏大致的文字思路

    以扫雷游戏为例,我们要先用代码设计一个整体的游戏框架(先要包含play和exit的界面,根据输入的数字执行开始游戏或退出游戏或重新输入),然后初始化“雷”表和“展示”表,再“埋”雷,最后排查雷,按这样的思路就可以制作扫雷游戏了。

三.需要掌握的知识

会使用VS2022或VS2019,正确使用头文件,基本字符(串)和占位符的使用,函数的创建及嵌套,全局变量和局部变量的灵活运用,分支和循环的运用,数组的创建及打印等。

四.代码操作

 我在这里使用VS2022。

        我们首先打开VS2022,在右边点击创建新项目。

 然后给自己的项目命名,之后在解决方案管理器上添加一个头文件game.h(专门用来包含头文件,定义函数及定义相关变量,放在其他.c文件最上方,可以直接链接过去,这样就不用每次都定义包含了),添加两个源文件game.c(用来专门实现相关函数)和test.c(专门用来搭建游戏框架,完善总逻辑),像我这里是这样的(我这里用中文备注上面的三个文件,你们用上面的英文备注就可以了):

 名称有点繁琐,先凑合着看吧。

首先,搭建游戏整体框架,如图:

 运行结果是这样的:

       这样就很方便的把这个游戏的总逻辑展现了出来,这需要很好掌握循环分支和输入方面的知识,想必大家看得懂。

此处要打印菜单,用do while循环,用switch选择,用scanf输入玩或退出。

如果这里的do while循环用为while循环也可以,但不好用for循环。

此处需包含

 

只是我把他放在扫雷相关定义.h里面去了,等下我会继续讲。

然后,我们可以去初始化棋盘(也就是创建数组)并将其初始化。

我们在设置的game函数中创建一个mine数组,还要一个show数组,前者用来布雷,后者用来展示。

我们挑初级9*9的来讲,这个实际上我们要2个11*11的数组,因为在我们平常玩扫雷的时候,不可避免的要点到“靠墙的”或“墙角的”格子,这种情况下我们在后期统计周围雷的数量时会“越界”,所以我们应该多留一层。

 分装到game函数(放在game.h中)中,把数组,行列,字符传参过去。

以上是相关定义,其中紫色部分这样定义很有用,方便后期更改游戏难度。(放在.h文件中)

 

 以上是相关函数实现,放在实现函数方面的game.c文件中。

注意:这里我要把整个数组传过去,还要对全数组

同理,我们设置一个DisplayBoard函数,来打印看看棋盘是什么样的。

 其中显示盘用字符“?”充满,布置雷的盘用字符“0”充满。

如图打印所示:

 这里的一到九是为了更好标记行和列,方便等下进行游戏。

假如不标记行和列,等下玩这个游戏的时候选行和列就比较痛苦,把那几行标记行和列的去掉对比一下就知道了。

 

 0的是布雷盘,一般不显示,?是展示盘,显示用。

打印好棋盘,我们要选择布雷,同理,定义,实现布雷函数,并放到game函数中去:

之前定义了EASY_COUNT为10,这里就不展示了。

 

此处我们要在main函数中先弄上srand((unsigned int)time(NULL))。

为什么传参传了个9*9呢,因为我布置雷要满足初级,且在9*9的格子里面不能越界

 

并在自创的.h文件中加上#include<stdlib.h>和#include<time.h>,用于生成随机数来随机布雷,我们看一下布雷的结果:

 

 雷已经布置好了,除开表示行和列的数字,刚好十个雷。

现在,我们同理,创建FindMine函数。

它在game.h中定义,在game.c中声明,这个时候要传两个数组,并且传9*9上去,毕竟我布置雷是在9*9的方格里布置的,我去找雷也应该在9*9里面找。

当win叠加到71时,说明游戏通关,挑战成功。

注意:我们这里有一个数字和一般字符的转换,如‘5’-‘0’=5,5+‘0’=5,这样就可以在接下来的GetMine函数中确定周围雷的数字,并转化为字符,打印在show数组上,让我们在玩这个“扫雷”中更有底气。

我们把这个数字返回,然后转化为字符,打印在show棋盘中。

我们看一下效果:

 

 继续玩下去,应该可以赢的。

总的代码在下面:

//game.h
#pragma once
#pragma warning(disable:4996)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void game();
#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 rows,int cols);//用于棋盘或数组的打印
void SetMine(char mine[ROWS][COLS],int row,int col);//布置雷
#define EASY_COUNT 10//为了仿照扫雷中简单模式10个雷而设置
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);//排查雷
int GetMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col ,int t,int k);//周围雷的个数消息
//game.c
#include"扫雷相关代码定义.h"
//>>>>>>>>>>>>>>>>>>大game函数实现
void game() 
{
	char mine[ROWS][COLS];//创建数组
	char show[ROWS][COLS];
	InitBoard(mine, ROWS, COLS,'0');//用于棋盘或数组的初始化
	InitBoard(show, ROWS, COLS,'?');//用于棋盘或数组的初始化
	DisplayBoard(mine, ROW, COL);//用于棋盘或数组的打印(理论上不可以打印出来)(理论上不可以打印出来)kk
	DisplayBoard(show, ROW, COL);//用于棋盘或数组的打印
	SetMine(mine, ROW, COL);//布置雷
	DisplayBoard(mine, ROW, COL);//用于棋盘或数组的打印(理论上不可以打印出来)(理论上不可以打印出来)kk
	FindMine(mine, show, ROW, COL);//排查雷
	

}
//>>>>>>>>>>>>>>>>>以下是小函数实现
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set)//用于棋盘或数组的初始化
{
	int a = 0;
	for (a = 0; a < rows; a++)
	{
		int b = 0;
		for (b = 0; b < cols; b++)
		{
			board[a][b] = set;
		}
	}
}
void DisplayBoard(char board[ROWS][COLS],int row,int col)//用于棋盘或数组的打印
{
	int a = 0;
	printf("--------------扫雷游戏--------------\n");
	for (a = 0; a <= row; a++)
	{
		printf("%d ",a);
	}
	printf("\n");
		int b = 0;
		for (b = 1; b <= col; b++)//循环打符号,满足条件
		{
			int c = 0;
			printf("%d ", b);
			for (c = 1; c <= col; c++)
			{
				printf("%c ", board[b][c]);//把字符'0'和'1'打印出来,打在棋盘上
			}
			printf("\n");
		}
	printf("--------------扫雷游戏--------------\n");
}
void SetMine(char mine[ROWS][COLS],int row,int col)//设置雷,在九九格里面
{
	
	int count = EASY_COUNT;
	   
	while (count) //count减到零就不去布置雷了
	{
		int x = rand() % row + 1;//随机数设雷,添加头文件和srand
	    int y = rand() % col + 1;//用数组来布雷,注意相关条件,会不会重复布雷
		if (mine[x][y] == '0')//如果这个位置没有埋雷
		{
			mine[x][y] = '1';//埋雷
			count--;
		}
	}//布置好雷我们可以先验证一下是否布置完毕,打印一下,看下方mine的数组
	DisplayBoard(mine, ROW, COL);//用于棋盘或数组的打印(理论上不可以打印出来)(理论上不可以打印出来)kk
	//DisplayBoard(show, ROW, COL);//用于棋盘或数组的打印dacuole
}
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col)//排查雷
{
	int t = 0;
	int k = 0;
	int win = 0;
	
	while (win<ROW*COL-EASY_COUNT)
	{
		printf("请输入要排查的坐标:(例如:3 5表示3行5列)>");
	    scanf("%d %d",&t,&k);
		if (t >= 1 && t <= row && k >= 1 && t <= col)
		{
			if (mine[t][k] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(mine, ROW, COL);//死的明白
				printf("有'1'的地方是雷哦,下次再接再厉\n");
				break;
			}
			else
			{
				win++;
				int count = 0;
				count=GetMine(mine,show,ROW,COL,t,k);//求周围8个格子有多少颗雷
				show[t][k] = count + '0';
				DisplayBoard(show, ROW, COL);//用于棋盘或数组的打印
			}
		}
		else
			printf("输入错误,请重新输入;>\n");
	}
	if (win == ROW * COL - EASY_COUNT)
	{
		printf("恭喜你,挑战成功\n");
		DisplayBoard(mine, ROW, COL);//赢的明白
	}
}
int GetMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col,int t,int k)
{
	return(mine[t - 1][k - 1] +
		mine[t - 1][k] +
		mine[t - 1][k + 1] +
		mine[t][k + 1] +
		mine[t + 1][k + 1] +
		mine[t + 1][k] +
		mine[t + 1][k - 1] +
		mine[t][k - 1] - 8 * '0');
}
//test.c
#include"扫雷相关代码定义.h"

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 {
		printf("准备好扫雷了吗\n");//此页为整体框架搭建
		menu();
		printf("请输入:>");
	scanf("%d",&input);
		switch (input)
		{
		case 1:
			printf("扫雷开始\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	}while (input);

	return 0;
}

小伙伴们可以大胆尝试一下,这个还蛮好玩的。

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值