//扫雷
#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实现简易扫雷游戏的更多相关文章

  1. 洛谷 P2670 扫雷游戏==Codevs 5129 扫雷游戏

    题目描述 扫雷游戏是一款十分经典的单机小游戏.在n行m列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格).玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有 ...

  2. 原生javascript扫雷游戏

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. Java练习(模拟扫雷游戏)

    要为扫雷游戏布置地雷,扫雷游戏的扫雷面板可以用二维int数组表示.如某位置为地雷,则该位置用数字-1表示, 如该位置不是地雷,则暂时用数字0表示. 编写程序完成在该二维数组中随机布雷的操作,程序读入3 ...

  4. JAVA_扫雷游戏(布置地雷)

    1.要为扫雷游戏布置地雷,扫雷游戏的扫雷面板可以用二维int数组表示.如某位置为地雷,则该位置用数字-1表示, 如该位置不是地雷,则暂时用数字0表示. 编写程序完成在该二维数组中随机布雷的操作,程序读 ...

  5. [LeetCode] Minesweeper 扫雷游戏

    Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...

  6. C语言二维数组实现扫雷游戏

    #include<stdio.h> //使用二维数组实现 扫雷 int main() { char ui[8][8]={ '+','+','+','+','+','+','+','+', ...

  7. 【Android】自己动手做个扫雷游戏

    1. 游戏规则 扫雷是玩法极其简单的小游戏,点击玩家认为不存在雷的区域,标记出全部地雷所在的区域,即可获得胜利.当点击不包含雷的块的时候,可能它底下存在一个数,也可能是一个空白块.当点击中有数字的块时 ...

  8. C#编写扫雷游戏

    翻看了下以前大学学习的一些小项目,突然发现有个项目比较有意思,觉得有必要把它分享出来.当然现在看来,里面有很多的不足之处,但因博主现在已经工作,没有时间再去优化.这个项目就是利用C#编写一个Windo ...

  9. [Swift]LeetCode529. 扫雷游戏 | Minesweeper

    Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...

随机推荐

  1. 软件推荐-有限元开发软件FELAC

    首页:http://yuanjisuan.cn/ 有限元语言及其编译器(Finite Element Language And it’s Compiler),以下简称FELAC是中国科学院数学与系统科 ...

  2. 用Django ORM实现树状结构

    前言 之前看对于用关系数据库实现树状结构的方法就知道一直做自关联的表,但是感觉自关联查询太慢了,最近看到一篇文章,感觉视野开拓了好多,文章:数据库表设计,没有最好只有最适合来自:微信. 下面就针对这里 ...

  3. MySQL 基础--字符类型

    ##=====================================================================================## MySQL支持的字符 ...

  4. WPF PrismDialog PopupWindowAction使用MetroWindow

    本示例必须在prism5.0版本以上 PopupWindowAction如何使用MetroWindow?   public class Window1ViewModel:BindableBase,II ...

  5. 6. ASP.NET MVC 5.0 中的HTML Helper【HTML 帮助类】

    这篇文章,我将带领大家学习HTML Helper.[PS:上一篇-->5.ASP.NET MVC 中的Area[区域]是什么] HTML Helpers是用来创建HTML标签进而创建HTML控件 ...

  6. Servlet案例7:jsp技术及案例

    jsp运行原理: 根据jsp文件创建java文件(servlet),并编译运行 第一次访问时会被翻译成servlet后执行 jsp三个指令: 1.page指令:页面翻译运行的属性的配置(通常使用默认) ...

  7. [Mac]如何让两个窗口各占半个屏幕

    OS X中的拆分视图El Capitan或更高版本允许您使用两个应用程序填充Mac屏幕,而无需手动移动和调整窗口大小. 进入拆分视图 按住 窗口左上角的全屏按钮  . 当您按住按钮时,窗口会缩小,您可 ...

  8. 干货—MySQL常见的面试题+索引原理分析!

    目录 MySQL索引的本质 MySQL索引的底层原理 MySQL索引的实战经验 面试 问:数据库中最常见的慢查询优化方式是什么? 同学A:加索引. 问:为什么加索引能优化慢查询? 同学A:...不知道 ...

  9. 详谈再论JAVA获取本机IP地址

    首先,你如果搜索“JAVA获取本机IP地址”,基本上搜到的资料全是无用的.比如这篇:http://www.cnblogs.com/zrui-xyu/p/5039551.html实际上的代码在复杂环境下 ...

  10. IDEA的maven配置

    刚接触maven的时候,也知道maven目录下有个setting文件可以设置远程maven库的地址,但自己实践的时候,发现setting文件的地址都被注释掉了,但是jar包还是能成功下载下来,那这个下 ...