基于easyx库的GUI扫雷项目

基于easyx库的GUI扫雷项目


0.观前提醒

本程序为本人原创,没有参考任何其他资料或博客,图片素材基于原版扫雷图片

制作带GUI的扫雷游戏项目主要是为了练习自己的C语言基础和学习使用图形化库,我已经将此项目上传了,欢迎大家点击下面链接直接下载。写这篇博客一是为了记录自己曾经练习写代码的过程,二是分享给更多感兴趣的朋友。我将项目捏碎了给大家讲解了出来,相信只要具有一定的耐心,即使基础很差的朋友,也能随便写出来!

源码里的游戏本体有很多步骤可以放入函数进行执行的,这样代码看起来更加简洁。由于我写这个游戏的时候在高铁上,有些不方便,所以我并没有进行功能合并,有兴趣的朋友,自己new个函数将功能合并吧

源码地址:基于easyx图形库做的GUI版扫雷


1.扫雷游戏项目效果展示

请添加图片描述


2.扫雷游戏项目基本信息

项目名称:扫雷

开发语言:C语言

开发作者:牟建波

开发环境:Visual Studio2019、EasyX图形库、Windows

开发时间:2023-03-12


3.扫雷游戏项目设计思路

请添加图片描述


4.扫雷游戏实现原理

4.1 头文件解析

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <windows.h> //SetConsoleTextAttribute()函数头文件
#include <graphics.h> //easyx图形库
#include <time.h> //srand()函数头文件


 头文件使用解释:																									   
 	1.使用#include<windows.h>头文件,是为了使用其中的SetConsoleTextAttribute()进行字体颜色修改,方便后期给雷标记颜色区分
 	2.使用#include<graphics.h>头文件,是为了使用eaxys函数库,进行鼠标交互和图形绘制								    
 	3.使用#include<time.h>头文件,是为了使用srand()函数,通过时间播种生成随机数去对应雷
 

4.2 素材解析

  • 扫雷项目中的素材,全部来自官方原版游戏截图和自己画的,我把素材全放在pic文件夹下了,如下图2中各种表情、方块、数字、地雷

  • 在项目中,我们会使用easyx图形库对图像进行提取使用,所以尽量将素材和游戏放在同一目录下,避免一些奇怪的错误

请添加图片描述

请添加图片描述


4.3 变量与矩形布局解析

//三重矩阵布局:我的想法是用三个16*16的矩阵,分别用来表示雷区、地雷的数量、方块的状态,然后将他们进行一张棋盘重合

//这样的布局,可以降低开发难度,调用时也更加不易弄晕矩阵
int Minefield_matrix[16][16] = {
   
    0 };//雷区矩阵
int Mine_Count_matrix[16][16] = {
   
    0 };//地雷计数矩阵
int Block_Status_matrix[16][16] = {
   
    0 };//方块状态矩阵

//公用循环变量:
//这里设定为全局变量,是因为后续会使用很多次,我懒得在里面加int,而且C89标准是不能在for里定义int i的
//所以为了照顾不同编译标准的读者,这里我将其定义为全局变量
int i = 0;
int j = 0;

//中转地雷数组:用于临时中转存储地雷
int Transfer_Mine_matrix[40] = {
   
    0 };

//方块状态flag
int IsMine_flag = 0;//0表示非雷,1表示雷
//游戏胜利flag
int Success_flag = 0;//0表示失败,1表示成功

4.4 随机雷的实现

//生成随机雷
	//思路:
	//1.雷随机生成 16*16=256 从左到右 1~256
	//2.随机生成40个[1,256]范围的随机数,通过对矩阵的位置,将对应的编号设置为雷
	//3.为防止生成的随机数有重复的,每生成一个随机数,就将这个数存入Transfer_Mine_matrix[40]这个中转地雷数组中
	//4.之后生成的随机数需与数组中的元素进行比较,若重复则不会保存在数组中

	srand((unsigned int)time(0));//通过时间播种生成随机数用于表示雷
	for (int Mine_Number = 0; Mine_Number < 40; Mine_Number++)
	{
   
   
		int Correct_Number_mine = 0;//合格的雷的随机数字
		Correct_Number_mine = rand() % 256 + 1; //生成1~256范围内随机数

		if (Correct_Number_mine < 0 || Correct_Number_mine > 256)//随机数不符合要求
		{
   
   
			Mine_Number--;
		}
		else//随机数符合要求
		{
   
   
			for (i = 0; i < 40; i++)
			{
   
   
				if (Transfer_Mine_matrix[i] == Correct_Number_mine)//如果合格的雷在中转地雷数组中存在
				{
   
   
					Mine_Number--;//不符合的雷去掉,雷数-1
					break;
				}
				if (Transfer_Mine_matrix[i] == 0)//如果合格的雷没有出现过,则存入中转地雷数组中 中转地雷数组初始化是0
				{
   
   
					Transfer_Mine_matrix[i] = Correct_Number_mine;
					break;
				}
			}
		}
	}

	//测试雷的位置
	for (int i = 0; i < 40; i++)
	{
   
   
		printf("%d ", Transfer_Mine_matrix[i]);
	}

随机雷生成测试结果图:

请添加图片描述


4.5 生成雷位置矩阵的实现

//生成雷的矩阵
//思路:通过Transfer_Mine_matrix中转地雷数组中的随机数,通过对应关系写入雷区矩阵Minefield_matrix[16][16]中,雷的位置表示为1,非雷的位置表示为0
	for (int length = 0; length < 40; length++)
	{
   
   
		int count = 0;//计数
		for (i = 0; i < 16; i++)
		{
   
   
			for (j = 0; j < 16; j++)
			{
   
   
				count++;
				if (Transfer_Mine_matrix[length] == count)
				{
   
   
					Minefield_matrix[i][j] = 1;
					IsMine_flag = 1;//1表示雷,0表示非雷
					break;
				}
			}
			if (IsMine_flag == 1)
			{
   
   
				break;
			}
		}
		IsMine_flag = 0;//初始化,以免影响下次循环
		count = 0;//初始化,以免影响下次循环
	}
	//雷矩阵调试
	for (int i = 0; i < 16; i++)
	{
   
   
		for (int j = 0; j < 16; j++)
		{
   
   
			if (Minefield_matrix[i][j] == 1)
			{
   
   
				colour(12);//是雷标记为红色
			}
			else
			{
   
   
				colour(15);//不是雷标记为白色
			}
			printf("%d ", Minefield_matrix[i][j]);//打印雷矩阵
		}
		colour(15);//让后续字体染色显示不为红色
		printf("\n");
	}
	system("pause");

生成雷位置矩阵调试结果图:

请添加图片描述


4.6 生成雷数矩阵的实现

雷数矩阵处理的想法:

请添加图片描述

  • 上图是我们对于一个矩阵四周遍历的常规过程,可以看出,我们进行遍历都是一边一边的进行遍历,由外向内进行遍历。当我们处理边界的是否就非常头疼了,这时我们可以使用循环不变量法
  • 循环不变量法:比如上图,就是我们在考虑边界问题的时候是非常头疼的,如果我们每边都考虑全部遍历完,就会出现很多边界考虑问题,但是如果我们把遍历方式都设置成一种,那么就让边界问题变成了一种情况,也就是上图的只遍历开始到最后一位的前一位,让下一次循环遍历剩下的元素,从而叫做循环不变量法
  • 但是我们在处理雷数矩阵的时候,要处理的时一个元素四周,所以直接使用循环不变量法不合适的。我们可以使用它的思想,进行雷数的计算
  • 这里我的想法是,先处理矩阵的四个角,然后处理去角的四边,那么我们就剩下了一个15*15的正方形了,处理正方形我们就有了一个通用的方法进行计算,如下图

请添加图片描述

//通过对matrix矩阵每个元素的周围八个元素计算雷数,并将雷数存入number[16][16]矩阵中
//number矩阵中1~8表示雷数,9表示该元素为雷
//通过对Minefield_matrix雷区矩阵每个元素的周围八个元素进行计算雷数,并将雷存入Mine_Count_matrix地雷计数矩阵中
//Mine_Count_martix地雷计数矩阵中,1~8表示周围雷数量,9表示该元素为雷
for (i = 0; i < 16; i++)
{
   
   
	int count = 0;
	for (j = 0; j < 16; j++)
	{
   
   
		count = 0;
		if (Minefield_matrix[i][j] == 1)//如果是雷设为9
		{
   
   
			Mine_Count_matrix[i][j] = 9;
			continue;
		}
		else
		{
   
   
			//思路:
			//1.先处理16*16矩阵的,四个边角,坐标为(0,0)、(0,15)、(15,0)、(15,15)
			//2.再处理矩形的四边,在处理过程把矩阵看成一个17*17的矩阵,这样是为了方便计数设计,数组溢出并不会有什么问题,因为我们没有使用它
			//3.最后我们会剩下一个规整15*15的正方形,然后处理每个方块的八个方向就可以了
			if (i == 0 && j == 0)//左上角
			{
   
   
				if (Minefield_matrix[0][1] == 1)//左上角方块右侧
					count++;
				if (Minefield_matrix[1][0] == 1)//左上角方块下侧
					count++;
				if (Minefield_matrix[1][1] == 1)//左上角方块斜右下侧
					count++;
			}
			else if (i == 0 && j == 15)//右上角
			{
   
   
				if (Minefield_matrix[0][14] == 1)//右上角方块左侧
					count++;
				if (Minefield_matrix[1][15] == 1)//右上角方块下侧
					count++;
				if (Minefield_matrix[1][14] == 1)//右上角方块斜左下侧
					count++;
			}
			else if (i == 15 && j == 0)//左下角
			{
   
   
				if (Minefield_matrix[15][1] == 1)//左下角方块右侧
					count++;
				if (Minefield_matrix[14][0] == 1)//左下角方块侧
					count++;
				if (Minefield_matrix[14][1] == 1)//左下角方块斜右上侧
					count++;
			}
			else if (i == 15 && j == 15)//右下角
			{
   
   
				if (Minefield_matrix[15][14] == 1)//右下角方块左侧
					count++;
				if (Minefield_matrix[14][15] == 1)//右下角
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值