【C语言】——扫雷游戏的实现(超详细!)

本文使用C语言实现扫雷游戏,以巩固所学知识。介绍了游戏功能,如通过菜单选择继续或退出,可排查和标记雷。阐述了游戏设计,采用两个11*11数组,一个存雷信息,一个展示给玩家。还讲解了多文件操作、各功能实现及细节补充,并给出源码和效果演示。

一、 前言

  扫雷游戏是小时候的经典小游戏,相信大家都玩过吧。今天,我们便自己实现扫雷游戏,以对前面学到的知识做一个巩固。

二、 扫雷游戏的功能说明

  • 使用控制台实现经典的扫雷游戏
  • 游戏可以通过菜单实现继续玩或者退出游戏
  • 扫雷的棋盘是 9 ∗ 9 9 * 9 99的格子
  • 可以排查雷
      (1)如果位置不是雷,就显示周围有几个雷
      (2)如果位置是雷,就被炸死,游戏结束
      (3)把除10个雷之外的所有非雷区域找出来,排雷成功,游戏结束
  • 可以标记雷
      (1)如果确定是雷,则标记上肯定的记号
      (2)如果不确定是雷,则标记上不确定的记号
      (3)如果正确标记10个雷的位置,挑战成功,游戏结束

三、 游戏的分析和设计

  首先,要设计出一个 9 ∗ 9 9*9 99的棋盘来存储雷的信息,很自然就想到创建一个 9 ∗ 9 9*9 99的数组来实现。
  我们可以用数字 1 1 1 来代表雷,如果这个位置为雷,我们就放置 0 0 0 ;非雷,就放置 1 1 1


  当我们访问 ( 3 , 3 ) (3,3) 3,3这个坐标时,该坐标不是雷,则我们统计它周围雷的个数是 2 2 2 .
在这里插入图片描述


  然而,当我们访问 ( 8 , 5 ) (8, 5) (8,5) 这个坐标时,我们访问周围橙色一圈的位置,统计雷的个数,我们会发现数组越界。

在这里插入图片描述


  怎么办呢?为了防止越界,我们在设计的时候,可以把数组扩大一圈,棋盘还是在中间 9 ∗ 9 9*9 99的位置,外面一圈不布置雷就行。所以我们的数组创建成 11 ∗ 11 11*11 1111会更好。

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/efa548a8dfc44908b8a1c277c8269d88.png
  但显然。这个棋盘时不能给玩家看到的。所以,我们需要再创建一个数组,是用来展现给玩家看的。我们将布置雷的数组称为 m i n e s mines mines,展现给玩家看的数组称为 s h o w show show
  同时,为了神秘, s h o w show show数组开始时初始化为 字符 ‘ ∗ ’ ‘*’ ,为了保持两个数组的一致性,以便可以用同一套函数处理, m i n e s mines mines数组最开始也初始化成 字符 ‘ 0 ’ ‘0’ ‘0’ 字符 ‘ 1 ’ ‘1’ ‘1’

如下图:

在这里插入图片描述

四、多文件操作


  当代码比较多时,我们往往会根据程序的功能,将代码拆分在多个文件之中。
  一般来说, 函数的声明、类型的声明放在头文件 ( . h ) (.h) .h中,函数的定义和函数的调用放在不同的源文件 ( . c ) (.c) (.c)中。

例如:

add.c

//函数的定义
 int Add(int x, int y) 
 {
    
     	
     return x + y; 
 }

add.h

//函数的声明 
int Add(int x, int y);

test.c

#include<stdio.h>
#include"add.h"//自己写的头文件用""包含

int main() 
{
    
     	
    int a = 10;
    int b = 20;
    //函数调用 	
    int c = Add(a, b);
	printf("%d\n", c); 	
return 0; 
}


运行结果:

在这里插入图片描述

图解:
在这里插入图片描述

  通常,放函数定义的源文件 ( . c ) (.c) .c和放函数声明的头文件 ( . h ) (.h) (.h)名字相同


  为什么要用多文件操作呢,好处如下:

  • 逻辑清晰
  • 方便多人协同,效率更高
  • 可以适当的隐藏代码


  这里,我们也采用多文件的形式

  • game.h : 文件中写游戏需要的数据类型和函数声明等
  • game.c :文件中写游戏中函数的实现等
  • test.c : 文件中写游戏的测试逻辑

五、 游戏菜单的实现

  开始游戏之前,往往需要有个菜单, 供玩家选择

要求:

1、 选择 ′ 1 ′ ' 1 ' 1 开始游戏,选择 ′ 0 ′ '0' 0 退出游戏
2、 选择其他选项,提示选择错误

代码实现:

test.c文件

#include<stdio.h>

//打印菜单
void menu(void)
{
   
   
	printf("**********************\n");
	printf("*****   1:play   *****\n");
	printf("*****   0:exit   *****\n");
	printf("**********************\n");
}

void game(void)
{
   
   
	//负责整个游戏逻辑的实现
}

int main()
{
   
   
	int a = 0;
	//do while循环,上来直接让玩家进行选择
	do
	{
   
   
		menu();//打印菜单
		printf("请选择: ");
		scanf(" %d", &a);	
		switch (a)
		{
   
   
		case 1:
			game();//进入“游戏”函数,开始玩游戏
			break;
		case 0:
			printf("游戏结束\n");//结束游戏
			break;
		default:
			printf("选择错误,请重新选择\n");//选择错误
			printf("\n");
			break;
		}
	} while (a);
	return 0;
}

注:game函数负责整个游戏逻辑的实现,稍后就讲

六、 游戏主逻辑的实现

  我们在test.c文件中,专门创建一个game函数来完成整个游戏逻辑的实现

游戏主逻辑:

  • 创建 m i n e s mines mines数组和 s h o w show show数组
  • 初始化两个数组
  • 布置雷
  • 打印棋盘( s h o w show show数组)
  • 进入循环
      (1)玩家选择排查雷还是标记雷
      (2)判断玩家是否被“炸死”
      (3)判断玩家是否成功挑战游戏

七、 游戏各功能的实现

  由于整个游戏代码都是对 m i n e s mines mines s h o w show show两个数组进行操作,这里我们不妨在头文件中用宏定义1,使代码更高效:

game.h文件

#include<stdio.h>

#define ROW 9//实际操作的行
#define COL 9//实际操作的列

#define ROWS  ROW + 2//扩充后的行
#define COLS  COL + 2//扩充后的列

#define easy_count 10//雷的个数

7.1 初始化棋盘

功能:

  • m i n e s mines mines函数全部初始化为 ′ 0 ′ '0' 0
  • s h o w show show函数全部初始化为 ′ ∗ ′ '*'


代码实现:
game.c文件

//初始化扫雷
void initialize(char arr[ROWS][COLS], int rows, int cols, char x)
{
   
   
	int i = 0;
	for (i = 0; i < rows; i++)
	{
   
   
		int j = 0;

		for (j = 0; j < cols; j++)
		{
   
   
			arr[i][j] = x;
		}
	}
}

7.2 随机生成雷

(1) 随机数的产生

  想要在 9 ∗ 9 9*9 99的棋盘中随机放置10个雷,我们可以通过行和列生成十组随机数来实现,那么怎么才能生成随机数呢?

  C语言中,提供了rand函数来生成随机数,他生成随机数的范围是0-RAND_MAXRAND_MAX依赖编译器的实现,大部分编译器是32767

原型如下:

int rand (void);

  rand函数的使用需包含头文件:<stdlib.h>

  但是,rand函数生成的随机数是伪随机的,并不是真正的随机数。虽然单次运行中不同的rand函数会产生不同的随机数,但每次程序运行同一个rand函数生成的随机数是相同的。这是因为rand函数是对一个叫 “种子” 的基准值进行运算产生的随机数,而rand函数默认的种子是 1。而我们要生成不同的随机数,就要让种子不断变化

  C语言中又提供了srand函数用来初始化随机数的生成器的

原型如下:

void srand(unsigned int seed)

  程序在调用rand函数前先调用srand函数,通过srand函数的参数seed来设置rand函数生产随机数的时候的种子,只要种子在变化,每次生成随机数序列也就变化起来了。
  但现在,问题又来了,要想rand生成随机数,那就得srand的种子是随机的;我现在想要一个随机数,你却要求我给你一个随机数才能生成随机数,这就矛盾了。
  那么有什么东西是一直在变的呢?
  时间!
  我们可以将时间作为种子,这样种子就一直在变,生成的随机数也是随机的了
  C语言提供了一个time函数,可以获取时间

原型如下:

time_t time (time_t* timer);

  
  time函数会返回当前的日历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运⾏时间之间的差值,单位是秒。返回类型是time_t类型,本质上是32位或64位的整型类型。
  

  • time函数的参数timer如果是非NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
  • 如果timer是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳2

  time函数需要包含头文件:<time.h>
  

  了解这些知识后,我们就可以生成随机数了。代码如下:

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

i
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值