1. //扫雷
  2. #include <windows.h>
  3. #include <windowsx.h>
  4. #include <strsafe.h>
  5. #include <time.h>
  6. //格子区域大小(DIVISIONS * DIVISIONS)
  7. #define DIVISIONS 20
  8. //地雷数
  9. #define MINECOUNT 40
  10.  
  11. //消息处理
  12. LRESULT CALLBACK DealMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  13. //写入地雷
  14. void SetMine(int(*pChess)[DIVISIONS]);
  15. //获取随机数
  16. unsigned int GetRand();
  17. //判断胜利
  18. bool Win(int(*pChess)[DIVISIONS], int *pNotClickCount, int *pClickCount);
  19. //重置
  20. void Reset(HWND hWnd,int(*pChess)[DIVISIONS], int(*pClick)[DIVISIONS]);
  21.  
  22. int WINAPI WinMain(
  23. HINSTANCE hInstance, // 当前实例句柄
  24. HINSTANCE hPrevInstance,// 前一实例句柄
  25. LPSTR lpCmdLine, // 指向命令行参数的指针
  26. int nCmdShow // 窗口的显示方式
  27. )
  28. {
  29. HWND hWnd;
  30. MSG msg;
  31. WNDCLASS wndClass;
  32.  
  33. wndClass.cbClsExtra = ;
  34. wndClass.cbWndExtra = ;
  35. wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//画刷背景BLACK_PEN
  36. wndClass.hCursor = LoadCursor(NULL, IDI_APPLICATION);
  37. wndClass.hIcon = LoadIcon(NULL, IDC_ARROW);
  38. wndClass.hInstance = hInstance;
  39. wndClass.lpfnWndProc = DealMessage;
  40. wndClass.lpszClassName = TEXT("MineSweeping");
  41. wndClass.lpszMenuName = NULL;
  42. wndClass.style = CS_HREDRAW | CS_VREDRAW;
  43.  
  44. if (!RegisterClass(&wndClass))
  45. {
  46. MessageBox(NULL, TEXT("注册类失败,请检查参数是否成功设置"), TEXT("提示"), MB_OK);
  47. }
  48.  
  49. hWnd = CreateWindow(TEXT("MineSweeping"), // 窗口类名称
  50. TEXT("扫雷"), // 窗口标题栏名称
  51. WS_OVERLAPPEDWINDOW, // 窗口样式
  52. CW_USEDEFAULT, // 窗口水平位置
  53. CW_USEDEFAULT, // 窗口垂直位置
  54. CW_USEDEFAULT, // 窗口宽度
  55. CW_USEDEFAULT, // 窗口高度
  56. NULL, // 父窗口句柄
  57. NULL, // 窗口菜单句柄
  58. hInstance, // 窗口实例句柄
  59. NULL); // 窗口创建参数
  60. if (!hWnd) // 新窗口创建失败
  61. {
  62. return FALSE;
  63. }
  64.  
  65. ShowWindow(hWnd, SW_SHOWNORMAL);
  66. UpdateWindow(hWnd);
  67.  
  68. while (GetMessage(&msg, NULL, , ))
  69. {
  70. TranslateMessage(&msg);
  71. DispatchMessage(&msg);
  72. }
  73.  
  74. return msg.wParam;
  75. }
  76.  
  77. LRESULT CALLBACK DealMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  78. {
  79. //初始化要用到的变量
  80. HDC hdc;
  81. PAINTSTRUCT ps;
  82. RECT rect;
  83. HBRUSH hBrush, hOldBrush;
  84. TEXTMETRIC tm;
  85. static int cxChar,cxCaps,cyChar;
  86.  
  87. //输出整形用的缓冲区
  88. TCHAR szBuffer[];
  89. size_t iTarget;
  90.  
  91. //地雷以及点击后雷个数存储区
  92. static int iChess[DIVISIONS][DIVISIONS];
  93. int(*pChess)[DIVISIONS] = iChess;
  94. //点击后记录点击事件存储区
  95. static int iClick[DIVISIONS][DIVISIONS];
  96. int(*pClick)[DIVISIONS] = iClick;
  97.  
  98. //pSize:当前一个格子宽高
  99. //p:通用
  100. static POINT pSize = { , }, p;
  101.  
  102. //未点击的格子
  103. int iNotClickCount;
  104. //已经点击的格子
  105. int iClickCount;
  106.  
  107. switch (uMsg)
  108. {
  109. case WM_CREATE:
  110. hdc = GetDC(hWnd);
  111. //初始化
  112. Reset(hWnd, pChess, pClick);
  113. //获取字体高度
  114. GetTextMetrics(hdc, &tm);
  115. cyChar = tm.tmHeight + tm.tmExternalLeading;
  116. //平均宽度
  117. cxChar = tm.tmAveCharWidth;
  118. //判断是否等宽字体
  119. cxCaps = (tm.tmPitchAndFamily & ? : ) * cxChar / ;
  120.  
  121. ReleaseDC(hWnd, hdc);
  122. return ;
  123. case WM_KEYDOWN:
  124. //在没有鼠标的情况下,键盘模拟鼠标操作
  125. ShowCursor(false);
  126. GetCursorPos(&p);
  127. ScreenToClient(hWnd, &p);
  128. p.x = max(, min(DIVISIONS - , p.x / pSize.x));
  129. p.y = max(, min(DIVISIONS - , p.y / pSize.y));
  130.  
  131. switch (wParam)
  132. {
  133. case VK_UP:
  134. p.y = max(, p.y - );
  135. break;
  136. case VK_DOWN:
  137. p.y = min(DIVISIONS - , p.y + );
  138. break;
  139. case VK_LEFT:
  140. p.x = max(, p.x - );
  141. break;
  142. case VK_RIGHT:
  143. p.x = min(DIVISIONS - , p.x + );
  144. break;
  145. case VK_HOME:
  146. p.x = p.y = ;
  147. break;
  148. case VK_END:
  149. p.x = p.y = DIVISIONS - ;
  150. break;
  151. case VK_RETURN:
  152. case VK_SPACE:
  153. SendMessage(hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(p.x * pSize.x, p.y * pSize.y));
  154. break;
  155. }
  156. p.x = (p.x * pSize.x) + (pSize.x / );
  157. p.y = (p.y * pSize.y) + (pSize.y / );
  158.  
  159. ClientToScreen(hWnd, &p);
  160. SetCursorPos(p.x, p.y);
  161. ShowCursor(true);
  162. return ;
  163. case WM_SIZE:
  164. //pSize每个格子大小,X宽,Y高
  165. pSize.x = LOWORD(lParam) / DIVISIONS;
  166. pSize.y = HIWORD(lParam) / DIVISIONS;
  167. return ;
  168. case WM_LBUTTONDOWN:
  169. p.x = GET_X_LPARAM(lParam) / pSize.x;
  170. p.y = GET_Y_LPARAM(lParam) / pSize.y;
  171. if (p.x >= DIVISIONS || p.y >= DIVISIONS)
  172. {
  173. MessageBeep();
  174. return ;
  175. }
  176. switch (iClick[p.x][p.y])
  177. {
  178. case :
  179. MessageBeep();
  180. return ;
  181. case :
  182. MessageBeep();
  183. return ;
  184. }
  185. //判断是否点击到了雷
  186. if (iChess[p.x][p.y] == -)
  187. {
  188. if (MessageBox(hWnd, TEXT("你踩到地雷了!"), TEXT("boom"), MB_OK) == IDOK)
  189. {
  190. Reset(hWnd,pChess, pClick);
  191. InvalidateRect(hWnd, NULL, true);
  192. }
  193. }
  194. else
  195. {
  196. //当前位置修改为点击过
  197. iClick[p.x][p.y] = ;
  198. //判断是否胜利
  199. if (Win(pClick, &iNotClickCount, &iClickCount))
  200. {
  201. if (MessageBox(hWnd, TEXT("you win!"), TEXT("wow"), MB_OK) == IDOK)
  202. {
  203. Reset(hWnd,pChess, pClick);
  204. }
  205. }
  206. //标题显示信息
  207. StringCchPrintf(szBuffer, sizeof(szBuffer), TEXT("当前已经翻出的区域数%d,剩余区域数%d"), iClickCount, iNotClickCount);
  208. StringCchLength(szBuffer, sizeof(szBuffer), &iTarget);
  209. SetWindowText(hWnd, szBuffer);
  210. //计算当前点击位置附近雷数
  211. for (int x = -; x <= ; x++)
  212. {
  213. for (int y = -; y <= ; y++)
  214. {
  215. //超出客户区的格子不计算
  216. if (p.x + x >= && p.x + x < DIVISIONS && p.y + y >= && p.y + y < DIVISIONS)
  217. {
  218. //当前格子不计算
  219. if (x != || y != ) {
  220. if (iChess[p.x + x][p.y + y] == -)
  221. {
  222. iChess[p.x][p.y]++;
  223. }
  224. }
  225. }
  226. }
  227. }
  228. }
  229. //重绘格子
  230. rect.left = p.x * pSize.x;
  231. rect.top = p.y * pSize.y;
  232. rect.right = (p.x + ) * pSize.x;
  233. rect.bottom = (p.y + ) * pSize.y;
  234. InvalidateRect(hWnd, &rect, true);
  235. return ;
  236. case WM_RBUTTONDOWN:
  237. p.x = GET_X_LPARAM(lParam) / pSize.x;
  238. p.y = GET_Y_LPARAM(lParam) / pSize.y;
  239. if (p.x >= DIVISIONS || p.y >= DIVISIONS)
  240. {
  241. MessageBeep();
  242. return ;
  243. }
  244. //当前格子标记地雷状态切换
  245. switch (iClick[p.x][p.y])
  246. {
  247. case :
  248. iClick[p.x][p.y] = ;
  249. break;
  250. case :
  251. iClick[p.x][p.y] = ;
  252. break;
  253. default:
  254. MessageBeep();
  255. return ;
  256. }
  257. //重绘格子
  258. rect.left = p.x * pSize.x;
  259. rect.top = p.y * pSize.y;
  260. rect.right = (p.x + ) * pSize.x;
  261. rect.bottom = (p.y + ) * pSize.y;
  262. InvalidateRect(hWnd, NULL, true);
  263. return ;
  264. case WM_MOUSEMOVE:
  265. //鼠标超出扫雷区域鼠标禁止点击
  266. p.x = GET_X_LPARAM(lParam) / pSize.x;
  267. p.y = GET_Y_LPARAM(lParam) / pSize.y;
  268. if (p.x >= DIVISIONS || p.y >= DIVISIONS)
  269. {
  270. SetCursor(LoadCursor(NULL, IDC_NO));
  271. }
  272. else
  273. {
  274. SetCursor(LoadCursor(NULL, IDC_ARROW));
  275. }
  276. return ;
  277. case WM_PAINT:
  278. hdc = BeginPaint(hWnd, &ps);
  279. //扫雷棋盘绘画
  280. for (int i = ; i < DIVISIONS; i++)
  281. {
  282. MoveToEx(hdc, pSize.x * i, , NULL);
  283. LineTo(hdc, pSize.x * i, pSize.y * DIVISIONS);
  284.  
  285. MoveToEx(hdc, , pSize.y * i, NULL);
  286. LineTo(hdc, pSize.x * DIVISIONS, pSize.y * i);
  287. }
  288. //扫雷点击绘画
  289. for (int x = ; x < DIVISIONS; x++)
  290. {
  291. for (int y = ; y < DIVISIONS; y++)
  292. {
  293. //0:未开过的格子,1:开过的格子,2:标记过的格子
  294. switch (iClick[x][y])
  295. {
  296. case :
  297. //每个格子背景变成灰色
  298. hBrush = CreateSolidBrush(RGB(, , ));hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
  299. Rectangle(hdc, x * pSize.x, y * pSize.y, (x + ) * pSize.x, (y + ) * pSize.y);
  300. SelectObject(hdc, hOldBrush);DeleteObject(hBrush);DeleteObject(hOldBrush);
  301.  
  302. //当前格子写入地雷数
  303. //地雷数颜色随地雷数改变
  304. switch (iChess[x][y])
  305. {
  306. case :
  307. SetTextColor(hdc, RGB(, , )); break;
  308. case :
  309. SetTextColor(hdc, RGB(, , )); break;
  310. case :
  311. SetTextColor(hdc, RGB(, , )); break;
  312. case :
  313. SetTextColor(hdc, RGB(, , )); break;
  314. case :
  315. SetTextColor(hdc, RGB(, , )); break;
  316. case :
  317. SetTextColor(hdc, RGB(, , )); break;
  318. case :
  319. SetTextColor(hdc, RGB(, , )); break;
  320. }
  321. SetBkMode(hdc, TRANSPARENT);
  322. StringCchPrintf(szBuffer, sizeof(szBuffer), TEXT("%d"), iChess[x][y]);
  323. StringCchLength(szBuffer, sizeof(szBuffer), &iTarget);
  324. TextOut(hdc, (x * pSize.x) + (pSize.x / ) - (cxChar / ), (y * pSize.y) + (pSize.y / ) - (cyChar / ), szBuffer, iTarget);
  325. break;
  326. case :
  327. hBrush = CreateSolidBrush(RGB(, , ));hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
  328. //画一个标记的旗子
  329. MoveToEx(hdc, (x * pSize.x) + (pSize.x / ), (y * pSize.y) + (pSize.y / ) - , NULL);
  330. LineTo(hdc, (x * pSize.x) + (pSize.x / ), (y * pSize.y) + (pSize.y / ) + );
  331.  
  332. Rectangle(hdc, (x * pSize.x) + (pSize.x / ), (y * pSize.y) + (pSize.y / ) - , (x * pSize.x) + (pSize.x / ) + , (y * pSize.y) + (pSize.y / ));
  333.  
  334. MoveToEx(hdc, (x * pSize.x) + (pSize.x / ) - , (y * pSize.y) + (pSize.y / ) + , NULL);
  335. LineTo(hdc, (x * pSize.x) + (pSize.x / ) + , (y * pSize.y) + (pSize.y / ) + );
  336.  
  337. SelectObject(hdc, hOldBrush);DeleteObject(hBrush);DeleteObject(hOldBrush);
  338. break;
  339. }
  340.  
  341. }
  342. }
  343.  
  344. EndPaint(hWnd, &ps);
  345. return ;
  346. case WM_DESTROY:
  347. PostQuitMessage();
  348. break;
  349. default:
  350. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  351. }
  352. return ;
  353. }
  354. //产生随机数
  355. unsigned int GetRand()
  356. {
  357. int r = rand();
  358. r = r % DIVISIONS;
  359. return r;
  360. }
  361.  
  362. //写入地雷
  363. void SetMine(int(*pChess)[DIVISIONS])
  364. {
  365. POINT pPoint;
  366. for (int i = ; i < MINECOUNT; i++)
  367. {
  368. while (true)
  369. {
  370. pPoint.x = GetRand();
  371. pPoint.y = GetRand();
  372. if (pChess[pPoint.x][pPoint.y] != -)
  373. {
  374. pChess[pPoint.x][pPoint.y] = -;
  375. break;
  376. }
  377. }
  378. }
  379. return;
  380. }
  381.  
  382. //判断获胜
  383. bool Win(int(*pChess)[DIVISIONS],int *pNotClickCount,int *pClickCount)
  384. {
  385. int i = ;
  386. for (int x = ; x < DIVISIONS; x++)
  387. {
  388. for (int y = ; y < DIVISIONS; y++)
  389. {
  390. if (pChess[x][y] == || pChess[x][y] == )
  391. {
  392. i++;
  393. }
  394. }
  395. }
  396. *pNotClickCount = i;
  397. *pClickCount = (DIVISIONS * DIVISIONS) - i;
  398. if (i - MINECOUNT == )
  399. {
  400. return true;
  401. }
  402. return false;
  403. }
  404.  
  405. //重置
  406. void Reset(HWND hWnd,int(*pChess)[DIVISIONS], int(*pClick)[DIVISIONS])
  407. {
  408. //防止随机数重复
  409. srand((unsigned(time(NULL))));
  410. SetCursor(LoadCursor(NULL, IDC_WAIT));
  411. for (int x = ; x < DIVISIONS; x++)
  412. {
  413. for (int y = ; y < DIVISIONS; y++)
  414. {
  415. pChess[x][y] = ;
  416. pClick[x][y] = ;
  417. }
  418. }
  419. //memset(pChess, 0, sizeof(pChess));
  420. //memset(pClick, 0, sizeof(pClick));
  421. SetMine(pChess);
  422. SetCursor(LoadCursor(NULL, IDC_ARROW));
  423. InvalidateRect(hWnd, NULL, true);
  424. return;
  425. }

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. SignalR 服务器系统配置要求

    SignalR 所支持的服务器版本..NET Framework 版本.IIS和其他组件. SignalR操作系统要求 SignalR组件能够运行在下面的服务器和客户端操作系统.需要注意的是使用Web ...

  2. BASH 正则表达式和文本处理工具

    本节内容 1.  什么是正则 2.  grep 3.  sed 4.  awk 5.  其他补充 一  什么是正则 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方 ...

  3. Jenkins内置环境变量的使用

    一.查看Jenkins有哪些环境变量 1.新建任意一个job 2.增加构建步骤:Execute shell 或 Execute Windows batch command 3.点击输入框下方的“可用环 ...

  4. 如何正确的使用Ubuntu以及安装常用的渗透工具集.

    文章来源i春秋 入坑Ubuntu半年多了  记得一开始学的时候基本一星期重装三四次=-= 尴尬了 觉得自己差不多可以的时候 就吧Windows10干掉了 c盘装Ubuntu 专心学习.   这里主要来 ...

  5. Shell-14--awk

    awk ' 条件1{ 动作1} 条件2{动作2}...' 文件名 awk处理数据是 先读取第一行 然后再去处理 printf 不会加入换行符,需要手动加入 print 会自动加换行 begin 是在后 ...

  6. 软件测试人员需要掌握的linux命令(一)

    有些技能可以事半功倍,熟练的使用这些命令可以提高工作效率,并且结合这些命令对测试过程中遇到的问题进行一些初步的定位. 一:目录与文件操作: ls 使用权限:所有人功能 : 显示指定工作目录下之内容(列 ...

  7. spring-boot(hello world)

    重拾程序,想不到从java开始,最近两周开搞web,从基本框架开始,仅做个人学习记录,遗漏之处望请海涵. 1.基本准备 开发环境win7: IDE  myeclipse Version: 2017 C ...

  8. 嵌入式小系统I2S接口调试总结

    最近调试了I2S.由于芯片里面硬件配置出现了几个错误,着实也把我折腾了一番,不过,最终 还是把它搞定了.为了加深理解,就做个笔记吧,方面以后查找和学习. 定义:I²S或I2S(英语:Inter-IC ...

  9. 排序算法系列:快速排序算法JAVA版(靠谱、清晰、真实、可用、不罗嗦版)

    在网上搜索算法的博客,发现一个比较悲剧的现象非常普遍: 原理讲不清,混乱 啰嗦 图和文对不上 不可用,甚至代码还出错 为了不误人子弟耽误时间,推荐看一些靠谱的资源,如[啊哈!算法]系列: https: ...

  10. $.parseJson()定义和用法

    $.parseJSON() 函数用于将符合标准格式的的JSON字符串转为与之对应的JavaScript对象. 例子: 这里首先给出JSON字符串集,字符串集如下: var data="  { ...