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 ...
随机推荐
- SignalR 服务器系统配置要求
SignalR 所支持的服务器版本..NET Framework 版本.IIS和其他组件. SignalR操作系统要求 SignalR组件能够运行在下面的服务器和客户端操作系统.需要注意的是使用Web ...
- BASH 正则表达式和文本处理工具
本节内容 1. 什么是正则 2. grep 3. sed 4. awk 5. 其他补充 一 什么是正则 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方 ...
- Jenkins内置环境变量的使用
一.查看Jenkins有哪些环境变量 1.新建任意一个job 2.增加构建步骤:Execute shell 或 Execute Windows batch command 3.点击输入框下方的“可用环 ...
- 如何正确的使用Ubuntu以及安装常用的渗透工具集.
文章来源i春秋 入坑Ubuntu半年多了 记得一开始学的时候基本一星期重装三四次=-= 尴尬了 觉得自己差不多可以的时候 就吧Windows10干掉了 c盘装Ubuntu 专心学习. 这里主要来 ...
- Shell-14--awk
awk ' 条件1{ 动作1} 条件2{动作2}...' 文件名 awk处理数据是 先读取第一行 然后再去处理 printf 不会加入换行符,需要手动加入 print 会自动加换行 begin 是在后 ...
- 软件测试人员需要掌握的linux命令(一)
有些技能可以事半功倍,熟练的使用这些命令可以提高工作效率,并且结合这些命令对测试过程中遇到的问题进行一些初步的定位. 一:目录与文件操作: ls 使用权限:所有人功能 : 显示指定工作目录下之内容(列 ...
- spring-boot(hello world)
重拾程序,想不到从java开始,最近两周开搞web,从基本框架开始,仅做个人学习记录,遗漏之处望请海涵. 1.基本准备 开发环境win7: IDE myeclipse Version: 2017 C ...
- 嵌入式小系统I2S接口调试总结
最近调试了I2S.由于芯片里面硬件配置出现了几个错误,着实也把我折腾了一番,不过,最终 还是把它搞定了.为了加深理解,就做个笔记吧,方面以后查找和学习. 定义:I²S或I2S(英语:Inter-IC ...
- 排序算法系列:快速排序算法JAVA版(靠谱、清晰、真实、可用、不罗嗦版)
在网上搜索算法的博客,发现一个比较悲剧的现象非常普遍: 原理讲不清,混乱 啰嗦 图和文对不上 不可用,甚至代码还出错 为了不误人子弟耽误时间,推荐看一些靠谱的资源,如[啊哈!算法]系列: https: ...
- $.parseJson()定义和用法
$.parseJSON() 函数用于将符合标准格式的的JSON字符串转为与之对应的JavaScript对象. 例子: 这里首先给出JSON字符串集,字符串集如下: var data=" { ...