#include
#include// 用于InitCommonControls
#pragma comment(lib, "comctl32.lib") // 用于InitCommonControls
// 常量
const int WINDOW_STYLES = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION; // 窗口风格
const int MAX_WIDTH = 30; // 雷区最大宽度
const int MAX_HEIGHT = 25; // 雷区最大高度
const int FLAF_NULL = 0; // 格子无标记
const int FLAG_CAVEAT = 1; // 警告标记
const int FLAG_QUERY = 2; // 疑问标记
const int FLAG_OVERT = 3; // 已经打开的格子标记
const int FLAF_MINE = -1; // 地雷标记
const int CELL_SIZE = 25; // 格子大小
// 全局变量
static struct {
HINSTANCE hInst; // 应用程序句柄实例
HWND hWnd; // 主窗口句柄
HWND Button; // 重新开始按钮句柄
HWND lButton; // 左边剩余地雷按钮
HWND rButton; // 右边时间显示按钮
} Win;
static struct {
HWND hWnd [MAX_WIDTH][MAX_HEIGHT]; // 雷区按钮句柄
WNDPROC Proc; // 按钮原来消息处理函数地址
int Code [MAX_WIDTH][MAX_HEIGHT]; // 存储数据
int Flag [MAX_WIDTH][MAX_HEIGHT]; // 用户标记
}MineField;
static struct {
int Width; // 雷区宽度
int Height; // 雷区高度
int CellNum; // 剩下的安全格子数量
int Rated_MineNum; // 额定地雷数量
int MineNum; // 剩余地雷数量
int time; // 时间
bool timeOn;
}Game;
void toString(int val, char* string, int StringLen)
{ // 整数转换文本,本程序使用Unicode字符集,字符串长度需要大于2
char str [32];
int i = 0;
if (StringLen < 2) {
return;
}
_itoa_s(val, str, 10);
while ((i < 32) && (i < (StringLen / 2 - 1))) {
string [i * 2] = str [i];
string [i * 2 + 1] = 0;
i ++;
}
string [i] = string [i + 1] = 0;
}
int GetMineNum(int x, int y) // 寻找周围地雷的数目
{
int i, j, a, b, num = 0;
for (i = -1; i < 2; i++) {
for (j = -1; j < 2; j++) {
a = x + i;
b = y + j;
if ((a > -1) && (b > -1) && (a < Game.Width) && (b < Game.Height)) {
if (MineField.Code [a][b] == FLAF_MINE) {
num ++;
}
}
}
}
return num;
}
void NewGame(void) // 新游戏
{
int i, j;
char text[32];
// 清空数组
for (i = 0; i < Game.Width; i++) {
for (j = 0; j < Game.Height; j++) {
MineField.Flag [i][j] = FLAF_NULL;
MineField.Code [i][j] = 0;
SetWindowText(MineField.hWnd [i][j], L" ");
}
}
// 埋放地雷
srand(GetTickCount()); // 使用系统时间作为随机数种子
for (int k = 0; k < Game.Rated_MineNum; k++) {
i = rand() % Game.Width;
j = rand() % Game.Height;
if (MineField.Code [i][j] == FLAF_MINE) {
k --; // 已经有地雷,埋放失败
}else {
MineField.Code [i][j] = FLAF_MINE;
}
}
// 设置数字 显示周围地雷数量
for (i = 0; i < Game.Width; i++) {
for (j = 0; j < Game.Height; j++) {
if (MineField.Code [i][j] != FLAF_MINE) {
MineField.Code [i][j] = GetMineNum(i, j);
}
}
}
toString(Game.Rated_MineNum, text, 32);
SetWindowText(Win.lButton, (LPCTSTR) text);
SetWindowText(Win.rButton, L"0");
SetWindowText(Win.Button, L"∩_∩");
Game.time = 0;
Game.timeOn = false;
Game.MineNum = Game.Rated_MineNum;
Game.CellNum = Game.Width * Game.Height - Game.Rated_MineNum;
}
void OvertMine(void) // 显示地雷
{
char text[6], num;
Game.timeOn = false;
for (int i = 0; i < Game.Width; i++) {
for (int j = 0; j < Game.Height; j++) {
num = MineField.Code [i][j];
toString(num, text, 6);
SetWindowText(MineField.hWnd [i][j], num == FLAF_MINE ? L"雷" : (LPCTSTR) text);
}
}
}
// 雷区按键处理
void MineSub(int x, int y, bool LButton = true) {
int i, j, Num;
char text[32];
// 坐标范围检查
if ((x < 0) || (x >= Game.Width) ||
(y < 0) || (y >= Game.Height)) {
return;
}
Num = MineField.Code [x][y];
if (LButton) {
if ((MineField.Flag [x][y] == FLAG_CAVEAT) ||
MineField.Flag [x][y] == FLAG_OVERT) {
return;
}
Game.timeOn = true;
MineField.Flag [x][y] = FLAG_OVERT;
if (Num == FLAF_MINE) {
OvertMine();
SetWindowText(Win.Button, L">_<");
MessageBox(Win.hWnd, L"您踩到地雷啦,哈哈", L"您输了", 0);
NewGame();
return;
}else {
toString(Num, text, 6);
SetWindowText(MineField.hWnd [x][y], (LPCTSTR) text);
Game.CellNum --;
if (Game.CellNum == 0) {
OvertMine();
MessageBox(Win.hWnd, L"恭喜你过关!", L"过关", 0);
NewGame();
return;
}
if (Num == 0) {
for (i = -1; i < 2; i++) {
for (j = -1; j < 2; j++) {
if (Game.timeOn) { // 递归函数在重新开始后可能进入死循环
MineSub(x + i, y + j);
}
}
}
}
}
}else {
i = MineField.Flag [x][y];
if (i != FLAG_OVERT) {
if (i == FLAG_CAVEAT) {
Game.MineNum ++;
}
i = (i + 1) % 3;
MineField.Flag [x][y] = i;
SetWindowText(MineField.hWnd [x][y],
i == FLAF_NULL ? L" " : i == FLAG_CAVEAT ? L"×" : L"?");
if (i == FLAG_CAVEAT) {
Game.MineNum --;
}
toString(Game.MineNum, text, 32);
SetWindowText(Win.lButton, (LPCTSTR) text);
}
}
}
// 雷区按钮事件捕捉过程
static LRESULT CALLBACK MineFieldProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int x = 0, y = 0, i, j;
for (i = 0; i < Game.Width; i++) {
for (j = 0; j < Game.Height; j++) {
if (MineField.hWnd [i][j] == hWnd) {
x = i;
y = j;
}
}
}
switch(uMsg) {
case WM_RBUTTONDOWN: // 鼠标右键按下
MineSub(x, y, false);
break;
case WM_KEYDOWN: // 键盘按键事件
switch(wParam) {
case VK_UP: // 上
y = y > 0 ? y - 1 : 0;
break;
case VK_DOWN: // 下
y = y < (Game.Height - 1) ? y + 1 : Game.Height - 1;
break;
case VK_LEFT: // 左
x = x > 0 ? x - 1 : 0;
break;
case VK_RIGHT: // 右
x = x < (Game.Width - 1) ? x + 1 : Game.Width - 1;
break;
}
SetFocus(MineField.hWnd [x][y]); // 设置焦点控件
}
return CallWindowProc(MineField.Proc, hWnd, uMsg, wParam, lParam);
}
// 窗体事件捕捉过程
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int id, msg;
char text[32];
switch (uMsg) {
case WM_TIMER:
if (Game.timeOn) {
Game.time ++;
toString(Game.time, text, 32);
SetWindowText(Win.rButton, (LPCTSTR) text);
}
break;
case WM_COMMAND: // 按钮发送的消息
id = LOWORD(wParam); // 获取按钮编号
msg = HIWORD(wParam); // 获取消息值
if (msg == BN_CLICKED) { // 单击消息
if ((HWND) lParam == Win.Button) {
NewGame();
}else if (((HWND)lParam != Win.lButton) && ((HWND)lParam != Win.rButton)) {
MineSub(id & 255, id >> 8);
}
}
break;
case WM_DESTROY: // 退出
PostQuitMessage(0);
break;
default: // 其他事件
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return FALSE;
}
// 入口过程
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int w, h;
char text[32];
MSG msg;
WNDCLASSEX wce;
RECT rect;
// 初始化全局变量
Win.hInst = hInstance;
Game.Width = 15;
Game.Height = 10;
Game.Rated_MineNum = 15;
InitCommonControls(); // 初始化通用组件库
// 设置窗口
wce.cbSize = sizeof(WNDCLASSEX);
wce.style = 0;
wce.lpfnWndProc = (WNDPROC) WndProc;
wce.cbClsExtra = wce.cbWndExtra = 0;
wce.hInstance = hInstance;
wce.hIcon = LoadIcon(NULL,IDI_APPLICATION); // 窗口的最小化图标为默认图标
wce.hCursor = LoadCursor(NULL,IDC_ARROW); // 窗口采用箭头光标
wce.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wce.lpszMenuName = NULL;
wce.lpszClassName = L"Window";
wce.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wce);
// 打开窗口
Win.hWnd = CreateWindow(L"Window", L"扫雷", WINDOW_STYLES, CW_USEDEFAULT,
CW_USEDEFAULT, 100, 100, NULL, NULL, hInstance, NULL);
if (Win.hWnd == NULL) {
return -1;
}
ShowWindow(Win.hWnd, nCmdShow);
// 调整客户区大小
GetWindowRect(Win.hWnd, &rect);
rect.right = rect.left + Game.Width * CELL_SIZE;
rect.bottom = rect.top + (Game.Height + 2) * CELL_SIZE;
AdjustWindowRect(&rect, WINDOW_STYLES, FALSE); // 根据客户区大小计算窗口大小
w = rect.right - rect.left; // 宽度 20*25 应该是 大于500
h = rect.bottom - rect.top; // 高度 15*25 应该是 大于375
MoveWindow(Win.hWnd, rect.left, rect.top, w, h, TRUE);
toString(Game.Rated_MineNum, text, 32);
Win.lButton = CreateWindow(L"Button", (LPCTSTR) text, WS_CHILD | WS_VISIBLE, 10, 5,
CELL_SIZE * 2, CELL_SIZE * 2 - 10, Win.hWnd, 0, hInstance, NULL);
Win.Button = CreateWindow(L"Button", L"∩_∩", WS_CHILD | WS_VISIBLE, (Game.Width - 2) / 2 * CELL_SIZE,
5, CELL_SIZE * 2, CELL_SIZE * 2 - 10, Win.hWnd, 0, hInstance, NULL);
Win.rButton = CreateWindow(L"Button", L"0", WS_CHILD | WS_VISIBLE, (Game.Width - 2) * CELL_SIZE - 5,
5, CELL_SIZE * 2, CELL_SIZE * 2 - 10, Win.hWnd, 0, hInstance, NULL);
if ((Win.lButton == NULL) || (Win.Button == NULL) || (Win.rButton == NULL)) {
return -1;
}
SetTimer(Win.hWnd, 0, 1000, NULL); // 设置时钟
// 创建按钮,成为雷区
for (int y = 0; y < Game.Height; y++) {
for (int x = 0; x < Game.Width; x++) {
MineField.hWnd [x][y] = CreateWindow(L"Button", L" ", WS_CHILD | WS_VISIBLE,
x * CELL_SIZE, (y + 2)* CELL_SIZE, CELL_SIZE, CELL_SIZE, Win.hWnd,
(HMENU)(y * 256 + x), hInstance, NULL);
if (MineField.hWnd [x][y] == NULL) {
return -1;
} // end if
// 改变按钮消息接收函数地址,在此之前,记录原地址
MineField.Proc = (WNDPROC)GetWindowLong(MineField.hWnd [x][y], GWL_WNDPROC);
SetWindowLong(MineField.hWnd [x][y], GWL_WNDPROC, (LONG)MineFieldProc);
} // next x
} // next y
NewGame();
SetFocus(MineField.hWnd [0][0]);
// 接收消息
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
代码很乱,将就看吧