WINAPI实现简易扫雷游戏
//扫雷
#include <windows.h>
#include <windowsx.h>
#include <strsafe.h>
#include <time.h>
//格子区域大小(DIVISIONS * DIVISIONS)
#define DIVISIONS 20
//地雷数
#define MINECOUNT 40 //消息处理
LRESULT CALLBACK DealMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
//写入地雷
void SetMine(int(*pChess)[DIVISIONS]);
//获取随机数
unsigned int GetRand();
//判断胜利
bool Win(int(*pChess)[DIVISIONS], int *pNotClickCount, int *pClickCount);
//重置
void Reset(HWND hWnd,int(*pChess)[DIVISIONS], int(*pClick)[DIVISIONS]); int WINAPI WinMain(
HINSTANCE hInstance, // 当前实例句柄
HINSTANCE hPrevInstance,// 前一实例句柄
LPSTR lpCmdLine, // 指向命令行参数的指针
int nCmdShow // 窗口的显示方式
)
{
HWND hWnd;
MSG msg;
WNDCLASS wndClass; wndClass.cbClsExtra = ;
wndClass.cbWndExtra = ;
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//画刷背景BLACK_PEN
wndClass.hCursor = LoadCursor(NULL, IDI_APPLICATION);
wndClass.hIcon = LoadIcon(NULL, IDC_ARROW);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = DealMessage;
wndClass.lpszClassName = TEXT("MineSweeping");
wndClass.lpszMenuName = NULL;
wndClass.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("注册类失败,请检查参数是否成功设置"), TEXT("提示"), MB_OK);
} hWnd = CreateWindow(TEXT("MineSweeping"), // 窗口类名称
TEXT("扫雷"), // 窗口标题栏名称
WS_OVERLAPPEDWINDOW, // 窗口样式
CW_USEDEFAULT, // 窗口水平位置
CW_USEDEFAULT, // 窗口垂直位置
CW_USEDEFAULT, // 窗口宽度
CW_USEDEFAULT, // 窗口高度
NULL, // 父窗口句柄
NULL, // 窗口菜单句柄
hInstance, // 窗口实例句柄
NULL); // 窗口创建参数
if (!hWnd) // 新窗口创建失败
{
return FALSE;
} ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK DealMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//初始化要用到的变量
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
HBRUSH hBrush, hOldBrush;
TEXTMETRIC tm;
static int cxChar,cxCaps,cyChar; //输出整形用的缓冲区
TCHAR szBuffer[];
size_t iTarget; //地雷以及点击后雷个数存储区
static int iChess[DIVISIONS][DIVISIONS];
int(*pChess)[DIVISIONS] = iChess;
//点击后记录点击事件存储区
static int iClick[DIVISIONS][DIVISIONS];
int(*pClick)[DIVISIONS] = iClick; //pSize:当前一个格子宽高
//p:通用
static POINT pSize = { , }, p; //未点击的格子
int iNotClickCount;
//已经点击的格子
int iClickCount; switch (uMsg)
{
case WM_CREATE:
hdc = GetDC(hWnd);
//初始化
Reset(hWnd, pChess, pClick);
//获取字体高度
GetTextMetrics(hdc, &tm);
cyChar = tm.tmHeight + tm.tmExternalLeading;
//平均宽度
cxChar = tm.tmAveCharWidth;
//判断是否等宽字体
cxCaps = (tm.tmPitchAndFamily & ? : ) * cxChar / ; ReleaseDC(hWnd, hdc);
return ;
case WM_KEYDOWN:
//在没有鼠标的情况下,键盘模拟鼠标操作
ShowCursor(false);
GetCursorPos(&p);
ScreenToClient(hWnd, &p);
p.x = max(, min(DIVISIONS - , p.x / pSize.x));
p.y = max(, min(DIVISIONS - , p.y / pSize.y)); switch (wParam)
{
case VK_UP:
p.y = max(, p.y - );
break;
case VK_DOWN:
p.y = min(DIVISIONS - , p.y + );
break;
case VK_LEFT:
p.x = max(, p.x - );
break;
case VK_RIGHT:
p.x = min(DIVISIONS - , p.x + );
break;
case VK_HOME:
p.x = p.y = ;
break;
case VK_END:
p.x = p.y = DIVISIONS - ;
break;
case VK_RETURN:
case VK_SPACE:
SendMessage(hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(p.x * pSize.x, p.y * pSize.y));
break;
}
p.x = (p.x * pSize.x) + (pSize.x / );
p.y = (p.y * pSize.y) + (pSize.y / ); ClientToScreen(hWnd, &p);
SetCursorPos(p.x, p.y);
ShowCursor(true);
return ;
case WM_SIZE:
//pSize每个格子大小,X宽,Y高
pSize.x = LOWORD(lParam) / DIVISIONS;
pSize.y = HIWORD(lParam) / DIVISIONS;
return ;
case WM_LBUTTONDOWN:
p.x = GET_X_LPARAM(lParam) / pSize.x;
p.y = GET_Y_LPARAM(lParam) / pSize.y;
if (p.x >= DIVISIONS || p.y >= DIVISIONS)
{
MessageBeep();
return ;
}
switch (iClick[p.x][p.y])
{
case :
MessageBeep();
return ;
case :
MessageBeep();
return ;
}
//判断是否点击到了雷
if (iChess[p.x][p.y] == -)
{
if (MessageBox(hWnd, TEXT("你踩到地雷了!"), TEXT("boom"), MB_OK) == IDOK)
{
Reset(hWnd,pChess, pClick);
InvalidateRect(hWnd, NULL, true);
}
}
else
{
//当前位置修改为点击过
iClick[p.x][p.y] = ;
//判断是否胜利
if (Win(pClick, &iNotClickCount, &iClickCount))
{
if (MessageBox(hWnd, TEXT("you win!"), TEXT("wow"), MB_OK) == IDOK)
{
Reset(hWnd,pChess, pClick);
}
}
//标题显示信息
StringCchPrintf(szBuffer, sizeof(szBuffer), TEXT("当前已经翻出的区域数%d,剩余区域数%d"), iClickCount, iNotClickCount);
StringCchLength(szBuffer, sizeof(szBuffer), &iTarget);
SetWindowText(hWnd, szBuffer);
//计算当前点击位置附近雷数
for (int x = -; x <= ; x++)
{
for (int y = -; y <= ; y++)
{
//超出客户区的格子不计算
if (p.x + x >= && p.x + x < DIVISIONS && p.y + y >= && p.y + y < DIVISIONS)
{
//当前格子不计算
if (x != || y != ) {
if (iChess[p.x + x][p.y + y] == -)
{
iChess[p.x][p.y]++;
}
}
}
}
}
}
//重绘格子
rect.left = p.x * pSize.x;
rect.top = p.y * pSize.y;
rect.right = (p.x + ) * pSize.x;
rect.bottom = (p.y + ) * pSize.y;
InvalidateRect(hWnd, &rect, true);
return ;
case WM_RBUTTONDOWN:
p.x = GET_X_LPARAM(lParam) / pSize.x;
p.y = GET_Y_LPARAM(lParam) / pSize.y;
if (p.x >= DIVISIONS || p.y >= DIVISIONS)
{
MessageBeep();
return ;
}
//当前格子标记地雷状态切换
switch (iClick[p.x][p.y])
{
case :
iClick[p.x][p.y] = ;
break;
case :
iClick[p.x][p.y] = ;
break;
default:
MessageBeep();
return ;
}
//重绘格子
rect.left = p.x * pSize.x;
rect.top = p.y * pSize.y;
rect.right = (p.x + ) * pSize.x;
rect.bottom = (p.y + ) * pSize.y;
InvalidateRect(hWnd, NULL, true);
return ;
case WM_MOUSEMOVE:
//鼠标超出扫雷区域鼠标禁止点击
p.x = GET_X_LPARAM(lParam) / pSize.x;
p.y = GET_Y_LPARAM(lParam) / pSize.y;
if (p.x >= DIVISIONS || p.y >= DIVISIONS)
{
SetCursor(LoadCursor(NULL, IDC_NO));
}
else
{
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
return ;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
//扫雷棋盘绘画
for (int i = ; i < DIVISIONS; i++)
{
MoveToEx(hdc, pSize.x * i, , NULL);
LineTo(hdc, pSize.x * i, pSize.y * DIVISIONS); MoveToEx(hdc, , pSize.y * i, NULL);
LineTo(hdc, pSize.x * DIVISIONS, pSize.y * i);
}
//扫雷点击绘画
for (int x = ; x < DIVISIONS; x++)
{
for (int y = ; y < DIVISIONS; y++)
{
//0:未开过的格子,1:开过的格子,2:标记过的格子
switch (iClick[x][y])
{
case :
//每个格子背景变成灰色
hBrush = CreateSolidBrush(RGB(, , ));hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Rectangle(hdc, x * pSize.x, y * pSize.y, (x + ) * pSize.x, (y + ) * pSize.y);
SelectObject(hdc, hOldBrush);DeleteObject(hBrush);DeleteObject(hOldBrush); //当前格子写入地雷数
//地雷数颜色随地雷数改变
switch (iChess[x][y])
{
case :
SetTextColor(hdc, RGB(, , )); break;
case :
SetTextColor(hdc, RGB(, , )); break;
case :
SetTextColor(hdc, RGB(, , )); break;
case :
SetTextColor(hdc, RGB(, , )); break;
case :
SetTextColor(hdc, RGB(, , )); break;
case :
SetTextColor(hdc, RGB(, , )); break;
case :
SetTextColor(hdc, RGB(, , )); break;
}
SetBkMode(hdc, TRANSPARENT);
StringCchPrintf(szBuffer, sizeof(szBuffer), TEXT("%d"), iChess[x][y]);
StringCchLength(szBuffer, sizeof(szBuffer), &iTarget);
TextOut(hdc, (x * pSize.x) + (pSize.x / ) - (cxChar / ), (y * pSize.y) + (pSize.y / ) - (cyChar / ), szBuffer, iTarget);
break;
case :
hBrush = CreateSolidBrush(RGB(, , ));hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
//画一个标记的旗子
MoveToEx(hdc, (x * pSize.x) + (pSize.x / ), (y * pSize.y) + (pSize.y / ) - , NULL);
LineTo(hdc, (x * pSize.x) + (pSize.x / ), (y * pSize.y) + (pSize.y / ) + ); Rectangle(hdc, (x * pSize.x) + (pSize.x / ), (y * pSize.y) + (pSize.y / ) - , (x * pSize.x) + (pSize.x / ) + , (y * pSize.y) + (pSize.y / )); MoveToEx(hdc, (x * pSize.x) + (pSize.x / ) - , (y * pSize.y) + (pSize.y / ) + , NULL);
LineTo(hdc, (x * pSize.x) + (pSize.x / ) + , (y * pSize.y) + (pSize.y / ) + ); SelectObject(hdc, hOldBrush);DeleteObject(hBrush);DeleteObject(hOldBrush);
break;
} }
} EndPaint(hWnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return ;
}
//产生随机数
unsigned int GetRand()
{
int r = rand();
r = r % DIVISIONS;
return r;
} //写入地雷
void SetMine(int(*pChess)[DIVISIONS])
{
POINT pPoint;
for (int i = ; i < MINECOUNT; i++)
{
while (true)
{
pPoint.x = GetRand();
pPoint.y = GetRand();
if (pChess[pPoint.x][pPoint.y] != -)
{
pChess[pPoint.x][pPoint.y] = -;
break;
}
}
}
return;
} //判断获胜
bool Win(int(*pChess)[DIVISIONS],int *pNotClickCount,int *pClickCount)
{
int i = ;
for (int x = ; x < DIVISIONS; x++)
{
for (int y = ; y < DIVISIONS; y++)
{
if (pChess[x][y] == || pChess[x][y] == )
{
i++;
}
}
}
*pNotClickCount = i;
*pClickCount = (DIVISIONS * DIVISIONS) - i;
if (i - MINECOUNT == )
{
return true;
}
return false;
} //重置
void Reset(HWND hWnd,int(*pChess)[DIVISIONS], int(*pClick)[DIVISIONS])
{
//防止随机数重复
srand((unsigned(time(NULL))));
SetCursor(LoadCursor(NULL, IDC_WAIT));
for (int x = ; x < DIVISIONS; x++)
{
for (int y = ; y < DIVISIONS; y++)
{
pChess[x][y] = ;
pClick[x][y] = ;
}
}
//memset(pChess, 0, sizeof(pChess));
//memset(pClick, 0, sizeof(pClick));
SetMine(pChess);
SetCursor(LoadCursor(NULL, IDC_ARROW));
InvalidateRect(hWnd, NULL, true);
return;
}
WINAPI实现简易扫雷游戏的更多相关文章
- 洛谷 P2670 扫雷游戏==Codevs 5129 扫雷游戏
题目描述 扫雷游戏是一款十分经典的单机小游戏.在n行m列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格).玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有 ...
- 原生javascript扫雷游戏
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Java练习(模拟扫雷游戏)
要为扫雷游戏布置地雷,扫雷游戏的扫雷面板可以用二维int数组表示.如某位置为地雷,则该位置用数字-1表示, 如该位置不是地雷,则暂时用数字0表示. 编写程序完成在该二维数组中随机布雷的操作,程序读入3 ...
- JAVA_扫雷游戏(布置地雷)
1.要为扫雷游戏布置地雷,扫雷游戏的扫雷面板可以用二维int数组表示.如某位置为地雷,则该位置用数字-1表示, 如该位置不是地雷,则暂时用数字0表示. 编写程序完成在该二维数组中随机布雷的操作,程序读 ...
- [LeetCode] Minesweeper 扫雷游戏
Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...
- C语言二维数组实现扫雷游戏
#include<stdio.h> //使用二维数组实现 扫雷 int main() { char ui[8][8]={ '+','+','+','+','+','+','+','+', ...
- 【Android】自己动手做个扫雷游戏
1. 游戏规则 扫雷是玩法极其简单的小游戏,点击玩家认为不存在雷的区域,标记出全部地雷所在的区域,即可获得胜利.当点击不包含雷的块的时候,可能它底下存在一个数,也可能是一个空白块.当点击中有数字的块时 ...
- C#编写扫雷游戏
翻看了下以前大学学习的一些小项目,突然发现有个项目比较有意思,觉得有必要把它分享出来.当然现在看来,里面有很多的不足之处,但因博主现在已经工作,没有时间再去优化.这个项目就是利用C#编写一个Windo ...
- [Swift]LeetCode529. 扫雷游戏 | Minesweeper
Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...
随机推荐
- 2019.03.01 bzoj2555: SubString(sam+lct)
传送门 题意简述: 要求在线支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 思路: 考虑用lctlctlct来动态维护samsa ...
- [预打印]使用vbs给PPT(包括公式)去背景
原先博客放弃使用,几篇文章搬运过来 在 视图—>宏 内新建宏 '终极版 Sub ReColor() Dim sld As Slide Dim sh As Shape For Each sld I ...
- 【jenkins git】Failed to connect to repository:Error performing command:git.exe ls-remote-h
jenkins使用git源码管理报错:Failed to connect to repository:Error performing command:git.exe ls-remote-h 本机需要 ...
- 卷积在深度学习中的作用(转自http://timdettmers.com/2015/03/26/convolution-deep-learning/)
卷积可能是现在深入学习中最重要的概念.卷积网络和卷积网络将深度学习推向了几乎所有机器学习任务的最前沿.但是,卷积如此强大呢?它是如何工作的?在这篇博客文章中,我将解释卷积并将其与其他概念联系起来,以帮 ...
- EF db first 获取表名称
一直以来,使用DB FIRST的方式,想得到表名,最后一直不得其法.直到昨天晚上,反编译自己的程序集的时候,突然发现EF表结构和数据实体类的映射关系存在什么地方.然后就有了这篇文章. 咱们一步步来. ...
- 从理论到实践 全面理解HTTP/2
前言 为了降低加载时间,相信大多数人都做过如下尝试 Keep-alive: TCP持久连接,增加了TCP连接的复用性,但只有当上一个请求/响应完全完成后,client才能发送下一个请求 Pipelin ...
- ElasticSearch核心知识总结(一)es的六种搜索方式和数据分析
es的六种搜索方式 query string search GET /ecommerce/product/_search //查询所有数据 { "took": 4,//耗费几毫秒 ...
- .NET手记-为ASP.NET MVC程序集成Autofac
MVC Autofac总是会紧跟最新版本的ASP.NET MVC框架,所以文档也会一直保持更新.一般来讲,不同版本的框架集成Autofac的方法一般不变. MVC集成需要引用 Autofac.Mvc5 ...
- apache和tomcat的区别和联系
两者既有联系又有区别,是两个软件,可独立使用,也可整合使用.Apache是web服务器(静态解析,如HTML),本身只支持html,Web服务器专门处理HTTP请求(request),可以通过插件支持 ...
- 【sping揭秘】21、Spring动态数据源的切换
对于多个数据源的时候,我们如何切换不同的数据源进行数据库的操作呢? 当然我们可以直接定义2个DataSource,然后在每次获取connection的时候,从不同的DataSource中获取conne ...