Easyx-----c语言实现简易版扫雷

扫雷规则简介 

实现思路 

  • 设置雷

  • 把以雷为中心的九宫格数据都+1,雷除外

  • 对应坐标贴图

  • 把数据转换为界面

  • 鼠标点击打开格子 - - - 需要把格子盖起来 [不能直接输出图片,否则没办法做打开] 还需要处理标记的问题 - - - 加密处理 - - - 加密后不能和之前的图片数字冲突 - - - > 如果不是常规数据则输出盖子
  • 右键标记格子(不能左右键同时点击)

代码实现

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

#include<mmsystem.h>
#pragma comment(lib, "winmm.lib")

#define ROW 10	    //定义行列的常量
#define COL	10 
#define MineNum 10	//雷的数量
#define ImgSize	40	//图片的尺寸

//定义图片资源
IMAGE imgs[12];
void loadResource()
{
	for (int i = 0; i < 12; i++)
	{
		char imgPath[50] = { 0 };                         //字符串格式化
		sprintf_s(imgPath, "./images/%d.jpg", i);         //缓冲区(数组) 格式字符串 
//注意: 图片要一个挨着一个输出
		loadimage(&imgs[i], imgPath, ImgSize, ImgSize);   //多字节字符集
	}
}

bool isfirst = true;	//是不是第一次进来

//函数声明
void show(int map[][COL]);
void init(int map[][COL]);
void draw(int map[][COL]);
void mouseMsg(ExMessage* msg, int map[][COL]);
void boomBlank(int map[][COL], int row, int col);
int judge(int map[][COL], int row, int col);
int main()
{
	//创建窗口
	initgraph(400, 400/*,EW_SHOWCONSOLE*/);
	//播放开始音乐
	mciSendString("open ./images/start.mp3 alias bgm", NULL, 0, NULL);
	mciSendString("play bgm", NULL, 0, NULL);

	//扫雷地图
	int map[ROW][COL] = {0};
	init(map);

	//游戏主循环
	while (true)
	{
		//处理消息
		ExMessage msg;
		while (peekmessage(&msg, EM_MOUSE))    //一次把消息接收完
		{
			switch (msg.message)
			{
//不是左键就是右键
			case WM_LBUTTONDOWN:	           //鼠标左键和右键点击
			case WM_RBUTTONDOWN:
				mouseMsg(&msg, map);
				int ret = judge(map,msg.y/ImgSize, msg.x / ImgSize);		//点击之后判断
				if (ret == -1)
				{

					draw(map);
					int select = MessageBox(GetHWnd(), "怎么输了呢?敢再来一把吗?", "low B!", MB_OKCANCEL);
					if (select == IDOK)	//再来一把
					{
						//重新初始化
						init(map);
					}
					else  //退出
					{
						exit(0);
					}

				}
				else if(ret == 1)
				{

				}
				system("cls");
				printf("judege:%d\n", ret);
				show(map);
				break;
			}
		}
		draw(map);		
	}

	//show(map);
	getchar();
	return 0;
}

void show(int map[][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			printf("%2d ", map[i][k]);
		}
		printf("\n");
	}
}
//初始化数据
void init(int map[][COL])
{
	loadResource();
	//设置随机数种子
	srand((unsigned)time(NULL));

	//把map全部初始化为0
	memset(map, 0, sizeof(int) * ROW * COL);

	//随机设置十个雷 用-1表示 
	for (int i = 0; i < MineNum; )
	{
		//数组的有效下标 [0,9]
		int r = rand() % ROW;
		int c = rand() % COL;
//随机下标可能有重复的---需要判断当前位置是否有设置为雷
		if (map[r][c] == 0)
		{
			map[r][c] = -1;
			//只有执行了这里的代码,才成功设置了雷 -1 后++
			i++;
		}
	}

	//把以雷为中心的九宫格数据都+1,雷除外
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			//找到雷,并遍历雷所在的九宫格
			if (map[i][k] == -1)
			{
				for (int r = i-1; r <= i+1; r++)
				{
					for (int c = k-1; c <= k+1; c++)
					{
						//对周围的数据加1,注意要防止出现数组下标为-1的情况(越界)
						if ((r >= 0 && r < ROW && c >= 0 && c < COL) && map[r][c] != -1)
						{
							++map[r][c];
						}
					}
				}
			}
		}
	}

	//加密格子 遍历每一个元素,对每一个元素加一个数处理,让它与原来不同,就不会输出原来对应的图片
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			map[i][k] += 20;    //所有的都需要加密
		}
	}
}
//根据地图绘制
void draw(int map[][COL])    
{
	//贴图,根据map里面的数据,贴对应的图片
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
    //周围全是雷中间是8---周围没有雷中间是0
			if (map[i][k]>=0 && map[i][k]<=8)	//范围[0,8]
			{
				int index = map[i][k];	//0 1 2 3 4 5 6 7 8
				putimage(k * ImgSize, i * ImgSize, &imgs[index]);	
			}
			else if (map[i][k] == -1)
			{
				putimage(k * ImgSize, i * ImgSize, &imgs[9]);
			}
			else if (map[i][k] >= 19 && map[i][k] <= 28)  //画盖子---范围判断 最小和最大的
			{
				putimage(k * ImgSize, i * ImgSize, &imgs[10]);
			}
			else if(map[i][k] >= 39)	//-1 + 20 + 20
			{
				putimage(k * ImgSize, i * ImgSize, &imgs[11]);
			}
		}
	}
}
//鼠标操作数据
void mouseMsg(ExMessage* msg,int map[][COL])
{
/*
  鼠标的坐标怎么求?
  拿到鼠标相对于窗口的坐标---需要转为数组下标(每个格子都对应一个数组的位置)
  msg->x;
  msg->y;
  printf("%d %d\n",msg->x,msg->y);
*/
	//先根据鼠标点击的坐标求出对应的数组的下标 类似y=kx 通过下标+图片宽度可以求坐标 逆向即可
	int r = msg->y / ImgSize;    //x---r---行
	int c = msg->x / ImgSize;    //y---c---列
	//左键打开格子
	if (msg->message == WM_LBUTTONDOWN)
	{
		//什么时候能够打开,没有打开的时候就打开(只能点击1次有效数字不会再变化)
		if (map[r][c]>=19 && map[r][c]<=28)
		{
			//这个函数只能播放wav格式
			PlaySound("./images/click.wav", NULL, SND_ASYNC | SND_FILENAME);
			map[r][c] -= 20;        //如果每点一次 -20 会导致数据离谱---需要处理
			boomBlank(map, r, c);	//检测一下是不是空白格子,是,炸开,不是直接退出
			isfirst = true;
		}	
	}
	//右键标记格子
	else if (msg->message == WM_RBUTTONDOWN)
	{
		PlaySound("./images/rightClick.wav", NULL, SND_ASYNC | SND_FILENAME);
		//是否能够标记:如果没有打开就能标记
		if (map[r][c] >= 19 && map[r][c] <= 28)
		{
			map[r][c] += 20;         //再次加密
		}
		else if(map[r][c]>=39)       //再次点击能够取消
		{
			map[r][c] -= 20;
		}
	}
}
/*点击空白格子,连环爆开周围的所有空白格子还有数字  row col 是当前点击的格子的下标
  如果一个格子是空白,那它周围一定是数字或者是空白(一定没有雷)*/
void boomBlank(int map[][COL],int row,int col)
{	
	//判断row col位置是不是空白格子(如果不是直接退出)
	if (map[row][col] == 0)
	{
		for (int r = row-1; r <= row+1; r++)            //遍历九宫格,是空白直接炸开
		{
			for (int c = col-1; c <= col+1; c++)
			{
				if ((r>=0&&r<ROW&&c>=0&&c<COL)			//没越界
					&& map[r][c]>=19 && map[r][c]<=28)	//没有打开
				{
					//每一次调用都会播放一下
					if (isfirst)
					{
						PlaySound("./images/search.wav", NULL, SND_ASYNC | SND_FILENAME);
						isfirst = false;
					}

					map[r][c] -= 20;
					boomBlank(map, r, c);              //继续遍历新的九宫格,继续打开
				}
			}
		}
	}
	return;
}
//游戏结束条件 [每点击一次就判断一下] 输了返回 -1  没结束返回 0 赢了返回 1
int judge(int map[][COL],int row ,int col)
{
	//点到了雷,结束	输了
	if (map[row][col] == -1 || map[row][col] == 19)    //任何时候都可以判断
	{
		return -1;
	}
	//点完了格子,结束 赢了 点开了100 - 10 = 90 个格子(都点开了)
	int cnt = 0;
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			//统计打开的格子的数量
			if (map[i][k] >= 0 && map[i][k] <= 8)
			{
				++cnt;    //最终有90个
			}
		}
	}
	if (ROW*COL - MineNum == cnt)
	{
		return 1;
	}

	return 0;
}

素材  

  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qiuqiuyaq

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

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

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

打赏作者

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

抵扣说明:

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

余额充值