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