⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 saolei.cpp

📁 经典扫雷程序 和windows自带扫雷一模一样 供学习使用
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//by qf
//扫雷程序
//雷区用二维向量数组LeiQu表示,方便定义雷区大小。数组初始化为0,表示无雷的初始状态;布雷下去后,用100表示数组对应的砖下有雷;
//当对数组对应的砖操作时,数组改为bmp图像中对应的表示该状态小图的序号;若不能对它再进行操作;则数组对应元素再加50;
//整个雷区的界面显示(雷区、计时器、计数器、笑脸)实为贴图,而边框呈现则为画白灰线;
//若游戏结束或还未开始,置stop=1;已翻的砖数用LeiTurn表示,当除雷外其他的砖均被翻开,则获胜,游戏结束

#include <windows.h>
#include <stdlib.h>
#include <time.h>
#include <algorithm>
#include <vector>
#include <string>
#include <fstream>
using namespace std;

#include "resource.h"
#include "htmlhelp.h"                     //对应的在联接里添加htmlhelp.lib
#include "SaoLei.h"

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;           //声明主回调函数
BOOL CALLBACK DefineProc (HWND, UINT, WPARAM, LPARAM);           //声明对话框回调函数

int CtNum, TmNum, FcNum, LeiTurn;        //CtNum:计数器应显示的数; TmNum:计时器应显示的数,TmNum == 1000表示游戏未开始;
                                         //FcNum:笑脸应显示的表情(对应face图)
vector<vector<int > >	LeiQu;          
int LeiQuWidth,LeiQuHight,LeiNum;        //LeiQuWidth:雷区宽;LeiQuHight:雷区高;LeiNum:总布雷数
int iSelection,herotime[3];              //iSelection:游戏级别;herotime[3]:英雄榜初中高级时间
string heroname[3];                      //heroname[3]:英雄榜初中高级名字
bool stop,mark,color,sound;              //mark:mark=1,菜单中标记项被选中,右键点第二下出问号;否则为还原
                                         //color:color=1,菜单中颜色项被选中,界面显示为彩色;否则为黑白
                                         //sound:sound=1,菜单中声音项被选中,时间走、成功、失败有声音;否则没有


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPreInstance, PSTR szCmdline, int iCmdShow)
//Windows程序的入口函数,相当于C中的main,参数由操作系统装入,
//hInstance为当前实例句柄,hPrevInstance为前一个实例的句柄,szCmdLine为命令行指针,iCmdShow为显示窗口的状态
{
	static TCHAR szAppName[] = TEXT("SaoLei") ;
	HWND         hwnd;
	MSG          msg;
	WNDCLASS     wndclass;

	wndclass.style         = CS_HREDRAW | CS_VREDRAW ;//窗口类型,CS_HREDRAW表移动或改变到客户区的宽时重画整个窗口,
	                                                  //CS_VREDRAW表移动或改变到客户区的高时重画整个窗口
	wndclass.lpfnWndProc   = WndProc ;               //指向回调函数的指针
	wndclass.cbClsExtra    = 0 ;
	wndclass.cbWndExtra    = 0 ;
	wndclass.hInstance     = hInstance ;             //窗口的实例句柄
	wndclass.hIcon         = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_Lei)) ;//装图标
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;                 //装光标
	wndclass.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH) ;       //设背景为灰画刷
	wndclass.lpszMenuName  = szAppName ;                                    //菜单名字
	wndclass.lpszClassName = szAppName ;                                    //进程名

	if (!RegisterClass (&wndclass))                                         //将wndclass注册给操作系统
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;//异常处理
		return 0 ;
	}

	hwnd = CreateWindow  (szAppName,                            // window class name  //创建窗口//窗口注册给操作系统的名字
		                  TEXT ("扫雷"),                        // window caption     //窗口标题
		                  WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, // window style       //窗口风格
		                  400,                                  // initial x position //窗口的左上角的横坐标位置
		                  300,                                  // initial y position //窗口的左上角的纵坐标位置
		                  100,                                  // initial x size     //窗口横向大小,
						  100,                                  // initial y size     //窗口纵向大小
						  NULL,                                 // parent window handle//父窗口句柄,本程序没有
						  NULL,                                 // window menu handle  //菜单句柄,本程序没有
						  hInstance,                            // program instance handle//程序的实例句柄
						  NULL) ;                               // creation parameters    //创建参数,本程序没有

	ShowWindow (hwnd, iCmdShow) ;                              //设置窗口的显示状态,首次调用时状态为winmain里的状态参数
	                                                           //此时,操作系统调用回调函数响应wm_creat消息
	UpdateWindow (hwnd) ;                                      //通过发wm_paint消息来更新窗口的客户区

	while (GetMessage (&msg, NULL, 0, 0))                      //消息循环,从操作系统的消息队列中获得消息,直到获得退出消息退出消息循环
	{
		TranslateMessage (&msg) ;                              //翻译消息
		DispatchMessage (&msg) ;                               //把消息发送给操作系统,然后由操作系统再调用Wndproc函数!
	}

	return msg.wParam ;

}

int FacePainter (HWND hwnd, HDC hdc, HDC hdcMem, HBITMAP hFace, int cxClient, int cxFace, int cyFace)
//画笑脸区
{ 
		SelectObject (hdcMem, hFace) ;
		BitBlt (hdc, (cxClient-cxFace)/2, 15, cxFace, cyFace, hdcMem, 0, FcNum*cyFace, SRCCOPY) ;
		return 0 ;
}

int CounterPainter (HWND hwnd, HDC hdc, HDC hdcMem, HBITMAP hCounter, int cxCounter, int cyCounter)
//画计数器
{ 
		SelectObject (hdcMem, hCounter) ;
		BitBlt (hdc, 18, 15, cxCounter, cyCounter, hdcMem, 0, 11*cyCounter, SRCCOPY) ;
		BitBlt (hdc, 18+cxCounter, 15, cxCounter, cyCounter, hdcMem, 0, (11-(int(CtNum/10)- (int(CtNum/100))*10 ))*cyCounter, SRCCOPY) ;
		BitBlt (hdc, 18+2*cxCounter, 15, cxCounter, cyCounter, hdcMem, 0, (11-(CtNum- (int(CtNum/10))*10 ))*cyCounter, SRCCOPY) ;
		return 0 ;
}

int TimerPainter (HWND hwnd, HDC hdc, HDC hdcMem, HBITMAP hCounter, int cxClient, int cxCounter, int cyCounter)
//画计时器
{ 
		SelectObject (hdcMem, hCounter) ;
		BitBlt (hdc, cxClient-15-3*cxCounter, 15, cxCounter, cyCounter, hdcMem,
			0, (11- ((int(TmNum/100)) - (int(TmNum/1000))*10 ))*cyCounter, SRCCOPY) ;
		BitBlt (hdc, cxClient-15-2*cxCounter, 15, cxCounter, cyCounter, hdcMem, 
			0, (11-(int(TmNum/10)- (int(TmNum/100))*10 ))*cyCounter, SRCCOPY) ;
		BitBlt (hdc, cxClient-15-cxCounter, 15, cxCounter, cyCounter, hdcMem, 
			0, (11-(TmNum- (int(TmNum/10))*10 ))*cyCounter, SRCCOPY) ;

		return 0 ;
}

int BrickPainter (HWND hwnd, HDC hdc, HDC hdcMem, HBITMAP hBrick, int cxBrick, int cyBrick) 
//画雷区
{ 
	int i,j;
	SelectObject (hdcMem, hBrick) ;
	for (j = 0; j < LeiQuHight; j++)
		for (i = 0; i< LeiQuWidth; i++)
		{
			SelectObject (hdcMem, hBrick) ;
			BitBlt (hdc, i*cxBrick+10, j*cxBrick+55, cxBrick, cyBrick, hdcMem, 0, (LeiQu[i][j] % 50)*cyBrick, SRCCOPY) ;
		}

	return 0 ;
}

int MineLayer ( )                                          
//随机布雷
{
	int i, x, y ,r ;

	srand((unsigned)time(NULL));
	for (i = 0; i < LeiNum; i++)           //需布雷数为LeiNum
	{
		r = rand() % (LeiQuHight*LeiQuWidth) ;
		x = r % LeiQuWidth ;
		y = int(r/LeiQuWidth) ;
		if ( LeiQu[x][y] != 100 )         //砖下没布雷,则布雷,表现为对应数组元素设为100
			LeiQu[x][y] = 100 ;     
		else
			--i;
	}
	return 0 ;
}
 
int MineTurner (int x, int y)                              
//递归翻砖
{
	int i, j ,m;
	m = 0 ; 

	if (LeiQu[x][y] < 50)                         //砖可翻
	{
	for (i = -1; i <= 1; i++)                     //遍历周围8个砖,统计周围雷数
		for (j = -1; j <= 1; j++)
		{
		    if ( i==0 && j==0 )                  //自身除外
				continue;
			if ( (x+i<0) || (x+i>=LeiQuWidth) )  //边界区
				continue;
			if ( (y+j<0) || (y+j>=LeiQuHight) )  //边界区
				continue;
			if ( LeiQu[x+i][y+j] >= 100 )        //有雷
				m++;
		}
	LeiQu[x][y] = Blank - m ;                    //对应bmp中数字图的序号
	LeiQu[x][y] += 50 ;                          //设为不可操作
	}

	if (m == 0)                                  //周围没雷,递归翻周围8个砖
	  for (i = -1; i <= 1; i++)
		for (j = -1; j <= 1; j++)
		{
		    if ( i==0 && j==0 )
				continue ;
			if ( (x+i<0) || (x+i>=LeiQuWidth) )
				continue ;
			if ( (y+j<0) || (y+j>=LeiQuHight) ) 
				continue ;
			if (LeiQu[x+i][y+j] >= 50)
				continue ;
			MineTurner (x+i, y+j) ;
			LeiTurn++ ;
		}		

	return 0 ;
}

int FlagSetter (int x, int y)                                   
//设旗帜
{
	if ( (x<0) || (x>=LeiQuWidth) )       //不在雷区内,返回
		return 0 ;
	if ( (y<0) || (y>=LeiQuHight) )
		return 0 ;
	if (LeiQu[x][y]%100 == 0)            //没被翻开且没设旗帜,设旗帜,并加50设为不可操作
	{
		LeiQu[x][y] += Flag ;
		LeiQu[x][y] += 50 ;
		CtNum -- ;                       //剩余雷数减一
	}
	else if (LeiQu[x][y]%100 == 50+Flag) //已被设旗,状态还原为可操作,剩余雷数+1
	{
		LeiQu[x][y] -= Flag ;
		if (mark)                        //标记状态,已设旗情况下设为问号
			LeiQu[x][y] += QuestionUp ;
		LeiQu[x][y] -= 50 ;              //无标记状态,已设旗情况下还原为无雷无旗状态
		CtNum ++ ;
	}
	else if (LeiQu[x][y] == QuestionUp)  //标记状态,已设问号情况下还原为无雷无旗状态
		LeiQu[x][y] -= QuestionUp ;					

	return 0 ;
}

int Exploder (int x, int y)                                      
//爆炸
{
	int i, j ;

	stop = 1 ;                        //游戏结束
	FcNum = Cry ;                      //笑脸变为哭脸
	if(sound)                         //有声音
		PlaySound (TEXT ("434.wav"), NULL, SND_FILENAME | SND_ASYNC) ;//同时,需联接winmm.lib才能发声
	LeiQu[x][y] = Bomb ;              //踩到的那个雷设为爆炸
	for (i = 0; i < LeiQuWidth; i++)
		for (j = 0; j < LeiQuWidth; j++)
		{
			if ((LeiQu[i][j] == 100) || (LeiQu[i][j] == QuestionUp))
				LeiQu[i][j] = Mine ;   //翻开没有被找出来的雷
			else if (LeiQu[i][j] == 50+Flag)
				LeiQu[i][j] = MineError ;  //标记出找错的雷
			else
				continue ;
		}
	return 0 ;
}

int Succeed()                                                    
//游戏成功
{
	int i,j;

	stop = 1;                       //游戏结束
	FcNum = Laugh ;                 //笑脸变为开心
	if(sound)
		PlaySound (TEXT ("433.wav"), NULL, SND_FILENAME | SND_ASYNC) ;
	for (i = 0; i < LeiQuWidth; i++)
		for (j = 0; j < LeiQuWidth; j++)
		{
			if ((LeiQu[i][j] == 100) || (LeiQu[i][j] == QuestionUp))
				LeiQu[i][j] = 50+Flag ;         //没有被标记出来的雷加旗帜
			continue ;
		}
	return 0;
}

void OpenFile()                                               
//打开文件"SaoLei.txt",读取变量
{
	fstream file;
	file.open( "SaoLei.txt", ios_base::in );
	file >> LeiQuWidth >> LeiQuHight >> LeiNum >> iSelection  >> mark >> color >> sound 
		 >> herotime[0] >> herotime[1] >> herotime[2]>> heroname[0] >> heroname[1] >> heroname[2] ;
	if (LeiQuWidth == 0)         //文件里还没存东西或文件不存在
	{
		LeiQuWidth = LeiQuWidthL ;
		LeiQuHight = LeiQuHightL ;
		LeiNum = LeiNumL ;
		iSelection = IDM_LOW ;
		mark = 0 ;
		color = 1 ;
		sound = 0 ;
		int i ;
		for (i=0 ; i < 3 ;i++)
		{
			herotime[i] = 999 ;
			heroname[i] = TEXT("匿名") ;			
		}	
	}
	file.close();
}

void SaveFile()                                             
//保存变量到"SaoLei.txt"文件
{  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -