C++扫雷

实现功能:

1.左键翻开

2.右键标记

3.选择简单,中等,困难三个难度

4.左右键同时按下,当标记数量相匹配时自动翻开

5.角块不藏雷

6.需要自己配置图片(jpg格式),loadimage函数中有注释

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <graphics.h>
#include <easyx.h>
#include <windows.h>
#include <conio.h>
#include <Mmsystem.h>
#include <mciapi.h>
#pragma comment(lib,"winmm.lib")
#define SIZE 35

int ROW, COL, NUM;					//行数 列数 雷数
int count;							//已经翻开的个数
int c_mine;							//已经标记个数
int map[40][20];					//定义二维数组地图
IMAGE img[20];						//图片

//初始化函数
void GameInit() {
	srand((unsigned int)time(NULL));    //获得随机种子

	for (int i = 0; i < ROW+2; i++) {   //初始化地图
		for (int j = 0; j < COL+2; j++) {
			map[i][j] = 0;
		}
	}

	int n = 0;
	while (n < NUM) {					//随机布雷
		int r = rand() % ROW+1;
		int c = rand() % COL+1;

		if (map[r][c] == 0 ) {								//判断是否已经布雷
			if ((r == 1 && c == 1) || (r == 1 && c == COL) || (r == ROW && c == 1) || (r == ROW && c == COL)) {//角块不藏雷
				continue;
			}
			map[r][c] = -1;
			n++;
		}		
	}

	for (int i = 1; i <= ROW; i++) {	//填充数字
		for (int j = 1; j <= COL; j++) {
			if (map[i][j] != -1) {							//如果是雷则遍历九宫格填充数字
				for (int m = i - 1; m <= i + 1; m++) {          
					for (int n = j - 1; n <= j + 1; n++) {
						if (map[m][n] == -1) {
							map[i][j]++;
						}
					}
				}
			}
		}
	}

	for (int i = 1; i <= ROW; i++) {	//加密覆盖空白图片
		for (int j = 1; j <= COL; j++) {
			map[i][j] += 20;
		}
	}
}
//自动翻开零块
void OpenZero(int r,int c) {
	map[r][c] -= 20;
	count++;

	//递归翻开所有非雷块
	for (int m = r - 1; m <= r + 1; m++) {
		for (int n = c - 1; n <= c + 1; n++) {
			if (m >= 1 && m <= ROW && n >= 1 && n <= COL) {
				if (map[m][n] >= 19 && map[m][n] <= 28) {
					if (map[m][n] != 20) {
						map[m][n] -= 20;
						count++;
					}
					else {				//如果是零块继续递归翻开
						OpenZero(m, n);
					}
				}
			}
		}
	}
}
//游戏函数
int PlayGame() {
	MOUSEMSG msg = { 0 };			//定义鼠标对象
	int r, c;
	int m_count = 0;				//九宫格内标记的个数

	while (1) {
		msg = GetMouseMsg();		//获取鼠标信息

		if (msg.mkLButton && msg.mkRButton) {					//当左右键同时按下
			r = msg.x / SIZE + 1;
			c = msg.y / SIZE + 1;
			if (map[r][c] >= 0 && map[r][c] <= 7) {				//计算九宫格标记数量
				for (int m = r - 1; m <= r + 1; m++) {          
					for (int n = c - 1; n <= c + 1; n++) {
						if (map[m][n] >= 69) {
							m_count++;
						}
					}
				}
				if (m_count == map[r][c]) {						//如果标记数量等于中心数字,自动翻开
					for (int m = r - 1; m <= r + 1; m++) {          
						for (int n = c - 1; n <= c + 1; n++) {						
							if (map[m][n] == 20) {								//零块调用函递归数
								OpenZero(m, n);
							}
							else if (map[m][n]>20 && map[m][n]<=28) {			//数字块正常翻开
								map[m][n] -= 20;
								count++;
							}
							else if (map[m][n] == 19) {							//雷块游戏结束
								map[m][n] -= 20;
								return -1;
							}
						}
					}
				}
			}
		}

		switch (msg.uMsg) {										//判断左右键
		case WM_LBUTTONDOWN:									//左键翻开空白块
			r = msg.x / SIZE + 1;
			c = msg.y / SIZE + 1;

			if (map[r][c] >= 19 && map[r][c] <= 28) {		
				if (map[r][c] == 20) {
					OpenZero(r,c);
				}
				else {
					map[r][c] -= 20;
					count++;
				}
			}
			return(map[r][c]);
			break;
		case WM_RBUTTONDOWN:									//右键标记
			r = msg.x / SIZE + 1;
			c = msg.y / SIZE + 1;

			if (map[r][c] >= 19 && map[r][c] <= 28) {				//标记
				map[r][c] += 50;
				c_mine++;
			}
			else if (map[r][c] > 30) {								//取消标记
				map[r][c] -= 50;
				c_mine--;
			}
			return(map[r][c]);
			break;
		}
	}
}
//绘制函数
void GameDraw() {
	for (int i = 1; i <= ROW; i++) {      //遍历
		for (int j = 1; j <= COL; j++) {
			if (map[i][j] >= 0 && map[i][j] <= 8) {                //数字
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[map[i][j]]);
			}
			else if (map[i][j] >= 19 && map[i][j] <= 28) {		   //空白
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[10]);
			}
			else if (map[i][j] >= 69 && map[i][j] <= 78) {		   //标记
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[11]);
			}
		}
	}

	int temp = NUM - c_mine;              //展示剩余雷的个数
	wchar_t t[3];
	_itow_s(temp, t, 10);
	outtextxy(50, COL * SIZE, L"The number of remaining:");
	outtextxy(221, COL * SIZE, t);
	if (temp < 10) {
		putimage(230, COL * SIZE, &img[0]);
	}
}
//展示结果
void ShowResult() {
	for (int i = 1; i <= ROW; i++) {		//遍历
		for (int j = 1; j <= COL; j++) {
			if (map[i][j] == -1) {									//踩到的雷
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[9]);
			}
			if (map[i][j] >= 0 && map[i][j] <= 8) {					//数字
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[map[i][j]]);
			}
			else if (map[i][j] == 19) {
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[14]);	//未翻开的雷
			}
			else if (map[i][j] == 69) {
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[12]);	// 标记正确
			}
			else if (map[i][j] >= 70 && map[i][j] <= 78) {
				putimage((i - 1) * SIZE, (j - 1) * SIZE, &img[13]);	//标记错误
			}
		}
	}
}
//绘制主界面
void DrawMenu() {
	initgraph(400, 300);				//绘制界面和加载图片
	loadimage(&img[17], L"easy.jpg", 400, 100);
	loadimage(&img[18], L"mid.jpg",  400, 100);
	loadimage(&img[19], L"hard.jpg", 400, 100);
	putimage(0,   0, &img[17]);
	putimage(0, 100, &img[18]);
	putimage(0, 200, &img[19]);

	while (1) {
		MOUSEMSG msg = { 0 };
		int r, c;
		msg = GetMouseMsg();
		if (msg.uMsg == WM_LBUTTONDOWN) {
			if (msg.x >= 0 && msg.x <= 400) {			//简单模式
				if (msg.y > 0 && msg.y <= 100) {
					ROW = COL = 8;
					NUM = 10;
					break;
				}
				else if (msg.y > 100 && msg.y <= 200) {	//中等模式
					ROW = COL = 16;
					NUM = 40;
					break;
				}
				else if (msg.y > 200 && msg.y <= 300) {	//困难模式
					ROW = 30;
					COL = 16;
					NUM = 99;
					break;
				}
			}
		}
	}
}
//加载图片
void LoadImg() {
	loadimage(&img[0],  L"0.jpg",  SIZE, SIZE);
	loadimage(&img[1],  L"1.jpg",  SIZE, SIZE);
	loadimage(&img[2],  L"2.jpg",  SIZE, SIZE);
	loadimage(&img[3],  L"3.jpg",  SIZE, SIZE);
	loadimage(&img[4],  L"4.jpg",  SIZE, SIZE);
	loadimage(&img[5],  L"5.jpg",  SIZE, SIZE);
	loadimage(&img[6],  L"6.jpg",  SIZE, SIZE);
	loadimage(&img[7],  L"7.jpg",  SIZE, SIZE);
	loadimage(&img[8],  L"8.jpg",  SIZE, SIZE);
	loadimage(&img[9],  L"9.jpg",  SIZE, SIZE);			//点开的雷
	loadimage(&img[10], L"10.jpg", SIZE, SIZE);			//空
	loadimage(&img[11], L"11.jpg", SIZE, SIZE);			//标
	loadimage(&img[12], L"12.jpg", SIZE, SIZE);			//标记正确
	loadimage(&img[13], L"13.jpg", SIZE, SIZE);			//标记错误
	loadimage(&img[14], L"14.jpg", SIZE, SIZE);			//未标记的雷
	loadimage(&img[15], L"15.jpg", SIZE, SIZE);			//失败
}

int main() {
my_begin:;
	count = 0;				//计数初始化
	c_mine = 0;
	DrawMenu();
	LoadImg();

	HWND hwnd = initgraph(ROW * SIZE, COL * SIZE+20); //绘制游戏界面
	setbkcolor(WHITE);
	setfillcolor(WHITE);
	fillrectangle(0,0, ROW * SIZE, COL * SIZE + 20);
	settextcolor(BLACK);

	GameInit();
	while (1) {
		GameDraw();
		if (PlayGame() == -1) {			//失败
			ShowResult();

			mciSendString(L"open music01.wav alias m01", 0, 0, 0);   
			mciSendString(L"play m01", 0, 0, 0);              
			MessageBox(hwnd, L"WIN!", L"", MB_OK);
			mciSendString(L"close m01", 0, 0, 0);
			break;
		}
		if (ROW * COL - NUM == count) {	//成功
			ShowResult();

			mciSendString(L"open music02.wav alias m02", NULL, 0, NULL);    
			mciSendString(L"play m02", NULL, 0, NULL);          
			MessageBox(hwnd, L"Lose!", L"", MB_OK);
			mciSendString(L"close m02", NULL, 0, NULL);
			break;
		}
	}
	goto my_begin;
	closegraph();
	return 0;
}
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值