📄 saolei.cpp
字号:
//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 + -