win32之扫雷

小学期windows程序设计课作业,虽然不喜欢windows的东西,但是对API的东西完全没有抵抗力。

个人作品,资源和框架抄的windows的源代码,剩下功能都是自己实现和添加的。

http://download.csdn.net/detail/lvlawliet/4553381

上面是资源连接,不需要积分,我好吧。

来分析一下这个程序,先从main.cpp开始。

void OnCreate(HWND hwnd)
{
    KillTimer(hwnd, 100);
    b_IfFace   = FALSE;
    IsLoadMine = FALSE;
    IsOver     = FALSE;
    timer      = FALSE;

    //加载位图
    g_hBmMine   = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_MINE));
    g_BitFace   = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_FACE));
    g_BitNumber = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_NUMBER));

    g_FaceNUM  =  4;
    g_Number_1 = 11;
    g_Number_2 = 11;
    g_Number_3 = 11;

    //初始化位图
    for (int nxIndex = 0; nxIndex < nXClient; nxIndex++)
    {
        for (int nyIndex = 0; nyIndex < nYClient; nyIndex++)
        {
            g_Flag[nxIndex][nyIndex] = IDBITNUM_INIT;
            g_Bit[nxIndex][nyIndex]  = IDBITNUM_INIT;
        }
    }

    //初始化雷区
    int row, clm;
    srand((unsigned)GetTickCount());
    for (int nIndex = 0; nIndex < nMaxMine; nIndex++)
    {
        row = rand() % nXClient;
        clm = rand() % nYClient;

        while (g_Flag[row][clm] == IDBITNUM_MINE)
        {
            row = rand() % nXClient;
            clm = rand() %nYClient;
        }
        g_Flag[row][clm] = IDBITNUM_MINE;
    }
}
位图是你在资源文件里定义好的,使用方法:看好你需要图片里第几个小格的,基本上位图需要的图片都是几个相同规格的小图片组成的,从上到下,第一个编号是0,第二个是1,以此类推,当前位置需要哪个图片,就赋值给位图变量编号即可。

例如

g_Bit[nxIdex][nyIndex] = IDBITNUM_INIT;

IDBITUN_INIT表示没有点开小格的图片,这样就将雷区初始化了。


void OnDLGCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    int flag = 0;
    RECT rect;
    HWND p_hwnd = GetParent(hwnd);
    GetWindowRect(p_hwnd, &rect);
    CHAR DlgText[256] = {0};

    switch (LOWORD(wParam))
    {
    case IDOK:
        SendDlgItemMessage(hwnd, ID_EDITHEITH, WM_GETTEXT, 5, (LPARAM)DlgText);
        nYClient = cToNumber(DlgText, 0);
        if (nYClient > 0 && nYClient <= 39);
        else
            nYClient = 10, flag = 1;

        SendDlgItemMessage(hwnd, ID_EDITWIDTH, WM_GETTEXT, 5, (LPARAM)DlgText);
        nXClient = cToNumber(DlgText, 0);
        if (nXClient > 0 && nXClient <= 62);
        else
            nXClient = 10, flag = 1;

        SendDlgItemMessage(hwnd, ID_EDITMINE, WM_GETTEXT, 5, (LPARAM)DlgText);
        nMaxMine = cToNumber(DlgText, 0);
        if (nMaxMine > 0 && nMaxMine <= nXClient * nYClient);
        else
            nMaxMine = 10, flag = 1;

        if (flag == 1)
            MessageBox(NULL, "你丫连100以内的非零自然数都输入不对,脑残片吃多了吧!好好看说明书去。", "你脑残吧!!!", MB_OK);
        MoveWindow(p_hwnd, rect.left, rect.top, nXClient * 16 + 36,
                   nYClient * 16 + 126, TRUE);
        OnCreate(p_hwnd);
        InvalidateRgn(p_hwnd, NULL, TRUE);
        EndDialog(hwnd, 100);
        break;

    case IDCANCEL:
        EndDialog(hwnd, 100);
        break;
    }
}



BOOL CALLBACK ModalProc(HWND   hwnd,
                        UINT   nMsg,
                        WPARAM wParam,
                        LPARAM lParam)
{
    switch (nMsg)
    {
    case WM_COMMAND:
        OnDLGCommand(hwnd, wParam, lParam);
        break;

    case WM_SYSCOMMAND:
        if (SC_CLOSE == wParam)
        {
            EndDialog(hwnd, 100);
        }
    }
    return 0;
}

void OnModal(HWND hwnd, WPARAM wParam)
{
    DialogBox(g_hInst, MAKEINTRESOURCE(IDD_SETTING), hwnd, ModalProc);
}
关于菜单栏里面自定义窗口的调出,用DialogBox调出ModalProc函数即可。


void FindMine1(int x, int y)
{
    if ((x < nXClient && y < nYClient) && (x >= 0 && y >= 0))
    {
        if (g_Flag[x][y] == 0)
        {
            g_Flag[x][y] = IDBITNUM_SPASE;
            g_Bit[x][y]  = IDBITNUM_SPASE;
            FindMine1(x + 1, y);
            FindMine1(x - 1, y);
            FindMine1(x, y + 1);
            FindMine1(x, y - 1);
            FindMine1(x + 1, y - 1);
            FindMine1(x - 1, y - 1);
            FindMine1(x + 1, y + 1);
            FindMine1(x - 1, y + 1);
        }
        else if (g_Flag[x][y] != IDBITNUM_MINE)
        {
            g_Bit[x][y] = g_Flag[x][y];
        }
    }
    return;
}


void FindMine(int x, int y)
{
    for (int row = 0; row < nXClient; row++)
    {
        for (int clm = 0; clm < nYClient; clm++)
        {
            if (g_Flag[row][clm] == IDBITNUM_INIT)
            {
                for (int i = 0; i < 3; ++i)
                {
                    for (int j = 0; j < 3; ++j)
                    {
                        if (g_Flag[row - 1 + i][clm - 1 + j] == IDBITNUM_MINE)
                        {
                            g_Flag[row][clm]++;
                        }
                    }
                }
            }
        }
    }
    FindMine1(x, y);
}
从当前非雷点扩展开图,只需要递归搜索出当前点所能到达所有的有数方格及其之内的空格即可。


void IsMine()
{
    for (int row = 0; row < nXClient; row++)
    {
        for (int clm = 0; clm < nYClient; clm++)
        {
            for (int i = 0; i < 3; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    if (g_Flag[row - 1 + i][clm - 1 + j] == IDBITNUM_MINE)
                    {
                        g_Bit[row - 1 + i][clm - 1 + j] = g_Flag[row - 1 + i][clm - 1 + j];
                    }
                }
            }
            if (g_Flag[row][clm] == IDBITNUM_MINE)
                g_Bit[row][clm] = g_Flag[row][clm];
            else
            if (g_Flag[row][clm] != IDBITNUM_MINE && g_Bit[row][clm] == 14)
                g_Bit[row][clm] = 12;
        }
    }
    IsOver = TRUE;
}
如果失败,显示所有雷,如果一个空格标记为小旗,那么要显示为X雷,所以需要加判断对该位置位图重新赋值编号。


void DrawMine(HDC hdc)
{
    HDC hBmpDC = CreateCompatibleDC(hdc);       //创建DC
    HBITMAP hOldBmp = (HBITMAP)                 //保存旧位图
                      SelectObject(hBmpDC, g_hBmMine);

    //绘制位图
    for (int nxIndex = 0; nxIndex < nXClient; nxIndex++)
    {
        for (int nyIndex = 0; nyIndex < nYClient; nyIndex++)
        {
            int nXPos = nxIndex * 16 + 14;
            int nYPos = nyIndex * 16 + 72;
            BitBlt(hdc, nXPos, nYPos, 16, 16, hBmpDC, 0,
                   g_Bit[nxIndex][nyIndex] * 16, SRCCOPY);
        }
    }
    SelectObject(hBmpDC, hOldBmp);              //恢复旧位图
    DeleteDC(hBmpDC);
}
这个就是实现位图贴到窗口的过程,期间贴的是g_Bit数组的编号,所以,如果你想记录信息用g_Flag数组,如果要显示用g_Bit数组。


void checkwin()
{
    int flag = 1;
    for (int row = 0; row < nXClient; row++)
    {
        for (int clm = 0; clm < nYClient; clm++)
        {
            if (g_Bit[row][clm] == 0 && g_Flag[row][clm] != IDBITNUM_MINE)
                flag = 0;
        }
    }
    if (flag == 1)
    {
        for (int row = 0; row < nXClient; row++)
        {
            for (int clm = 0; clm < nYClient; clm++)
            {
                if (g_Flag[row][clm] == IDBITNUM_MINE)
                    g_Bit[row][clm] = 14;
            }
        }
        g_FaceNUM = 1;
        IsOver = TRUE;
    }
}

void OnLButtonUp(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    int nXPos = LOWORD(lParam) - 14;
    int nYPos = HIWORD(lParam) - 72;
    int row = nXPos / 16;
    int clm = nYPos / 16;

    if (IsOver == FALSE)
    {
        if ((row < nXClient && clm < nYClient) && (row >= 0 && clm >= 0))
        {
            if (g_Bit[row][clm] == 14);
            else
            if (g_Flag[row][clm] == IDBITNUM_MINE)
            {
                IsMine();
                g_Bit[row][clm] = 11;
                g_FaceNUM = 2;
            }
            else
            {
                g_FaceNUM = 4;
                FindMine(row, clm);
                checkwin();
            }
        }
    }
    InvalidateRgn(hwnd, NULL, FALSE);
}
因为没有实现鼠标滑动,所以末日down点坐标和up点坐标一样,先求出当前坐标,之后判断是否是雷,如果不是就展开图,最后判断一下是否当前状态已经赢了(checkwin函数),同时要注意你在鼠标的操作也伴随着Face的改变,所以不同结果也要给g_FaceNUM不同的编号。


void DrawShell(HDC hdc)
{
    HPEN hPen        = CreatePen(PS_SOLID, 3, RGB(255, 255, 255));
    HPEN hOldPen     =              (HPEN)SelectObject(hdc, hPen);
    HBRUSH hBrush    =      CreateSolidBrush(RGB( 179, 179, 179));
    HBRUSH hOldBrush =          (HBRUSH)SelectObject(hdc, hBrush);

    MoveToEx(hdc, g_Width - 13, 13, NULL);
    LineTo(hdc, g_Width - 13, 60);

    MoveToEx(hdc, 13, 60, NULL);
    LineTo(hdc, g_Width - 13, 60);

    MoveToEx(hdc, 1, 1, NULL);
    LineTo(hdc, g_Width, 1);

    MoveToEx(hdc, 1, 0, NULL);
    LineTo(hdc, 1, g_Heigth);

    MoveToEx(hdc, 13, g_Heigth - 9, NULL);
    LineTo(hdc, g_Width - 13, g_Heigth - 9);

    MoveToEx(hdc, g_Width - 13, 72, NULL);
    LineTo(hdc, g_Width - 13, g_Heigth - 10);

    SelectObject(hdc, hOldBrush);
    DeleteObject(hBrush);
    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
}


void DrawShell1(HDC hdc)
{
    HPEN hPen        = CreatePen(PS_SOLID, 3, RGB(150, 150, 150));
    HPEN hOldPen     =              (HPEN)SelectObject(hdc, hPen);
    HBRUSH hBrush    =      CreateSolidBrush(RGB( 200, 200, 200));
    HBRUSH hOldBrush =          (HBRUSH)SelectObject(hdc, hBrush);

    MoveToEx(hdc, 13, 13, NULL);
    LineTo(hdc, g_Width - 13, 13);

    MoveToEx(hdc, 13, 12, NULL);
    LineTo(hdc, 13, 60);

    SelectObject(hdc, hOldBrush);
    DeleteObject(hBrush);
    SelectObject(hdc, hOldPen);

    HPEN hPen1       = CreatePen(PS_SOLID, 3, RGB(150, 150, 150));
    HPEN hOldPen1    =              (HPEN)SelectObject(hdc, hPen1);

    MoveToEx(hdc, g_Width - 13, 69, NULL);
    LineTo(hdc, 11, 69);

    MoveToEx(hdc, 12, g_Heigth - 10, NULL);
    LineTo(hdc, 12, 69);

    SelectObject(hdc, hOldPen1);
    DeleteObject(hPen);
}
绘制窗口,因为现实有些立体感,所有需要在边框用不同颜色的线段勾勒....学过美术的同学想必很好理解,所有这两个函数主要作用就是用不同颜色的先勾勒上面的窗口,使其显得更有立体感。


主要函数就是这些了,下面是resource.rc里面的东西,.rc文件很好创建,如果你很熟悉也可以直接txt写。

//Microsoft Developer Studio generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/
#undef APSTUDIO_READONLY_SYMBOLS

/
// Chinese (P.R.C.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#pragma code_page(936)
#endif //_WIN32

#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//

1 TEXTINCLUDE DISCARDABLE
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE DISCARDABLE
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE DISCARDABLE
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/
//
// Dialog
//

IDD_SETTING DIALOG DISCARDABLE  0, 0, 129, 85
STYLE DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "自定义雷区"
FONT 9, "宋体"
BEGIN
    DEFPUSHBUTTON   "确定",IDOK,80,20,40,16
    PUSHBUTTON      "取消",IDCANCEL,80,46,40,16
    LTEXT           "高度(&H):",112,10,22,35,10,NOT WS_GROUP
    EDITTEXT        ID_EDITHEITH,46,20,25,12
    LTEXT           "宽度(&W):",113,10,37,35,10,NOT WS_GROUP
    EDITTEXT        ID_EDITWIDTH,46,35,25,12
    LTEXT           "雷数(&M):",111,10,52,35,10,NOT WS_GROUP
    EDITTEXT        ID_EDITMINE,46,50,25,12
END

IDD_ABOUT DIALOG DISCARDABLE  0, 0, 150, 68
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "关于扫雷"
FONT 10, "System"
BEGIN
    LTEXT           "仅仅测试,众多BUG,望且见谅。",112,10,10,120,100,NOT WS_GROUP
    LTEXT           "——————BY L.Lawliet", 120, 50,40, 120, 100, NOT WS_GROUP
END


/
//
// Menu
//

IDR_MAIN MENU FIXED IMPURE
BEGIN
    POPUP "游戏(&G)"
    BEGIN
        MENUITEM "开局(&N)\tF2",                ID_START
        MENUITEM SEPARATOR
        MENUITEM "初级(&B)",                    ID_FIRST
        MENUITEM "中级(&I)",                    ID_MID
        MENUITEM "高级(&E)",                    ID_HIGHT
        MENUITEM "自定义(&C)...",               ID_DIY
        MENUITEM SEPARATOR
        MENUITEM "保存(&S)",                    ID_SIN
        MENUITEM "读取(&L)",                    ID_LOAD
        //MENUITEM "颜色(&L)",                  ID_COLOR
        MENUITEM "声音(&M)",                    ID_SOUND
        MENUITEM SEPARATOR
        MENUITEM "扫雷英雄榜(&T)...",           ID_HERO
        MENUITEM SEPARATOR
        MENUITEM "退出(&X)",                    ID_EXIT
    END
    POPUP "帮助(&H)"
    BEGIN
        //MENUITEM "目录(&C)\tF1",              ID_DIR
        //MENUITEM "查找帮助主题(&S)...",       ID_HELPINFO
        MENUITEM "帮助(&H)",                    ID_HELP
        MENUITEM SEPARATOR
        MENUITEM "关于扫雷(&A)...",             ID_ABOUT
    END
END


/
//
// Bitmap
//

IDB_MINE                BITMAP  FIXED IMPURE    "./res/mine.bmp"
IDB_FACE                BITMAP  FIXED IMPURE    "./res/face.bmp"
IDB_NUMBER              BITMAP  FIXED IMPURE    "./res/number.bmp"

/
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_MAIN                ICON    DISCARDABLE     "./res/main.ico"

/
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
    IDD_ABOUT, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 163
        TOPMARGIN, 7
        BOTTOMMARGIN, 61
    END
END
#endif    // APSTUDIO_INVOKED


/
//
// Accelerator
//

501 ACCELERATORS FIXED IMPURE
BEGIN
    VK_F1,          590,                    VIRTKEY
    VK_F2,          510,                    VIRTKEY
END

#endif    // Chinese (P.R.C.) resources
/



#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
//


/
#endif    // not APSTUDIO_INVOKED
主要的是位图图片和ID的连接,还有菜单栏。



好的,以下是一个简单的面向对象的扫雷小游戏代码示例: ```python import random class Minesweeper: def __init__(self, width, height, num_mines): self.width = width self.height = height self.num_mines = num_mines self.board = [[0 for _ in range(width)] for _ in range(height)] self.mines = [] self.hidden = [[True for _ in range(width)] for _ in range(height)] self.game_over = False # randomly place mines on the board while len(self.mines) < num_mines: x = random.randint(0, width - 1) y = random.randint(0, height - 1) if (x, y) not in self.mines: self.mines.append((x, y)) self.board[y][x] = "X" # calculate the number of mines adjacent to each square for y in range(height): for x in range(width): if self.board[y][x] == "X": continue count = 0 for dy in [-1, 0, 1]: for dx in [-1, 0, 1]: if dy == 0 and dx == 0: continue if 0 <= y + dy < height and 0 <= x + dx < width and self.board[y + dy][x + dx] == "X": count += 1 self.board[y][x] = count def __str__(self): result = "" for y in range(self.height): for x in range(self.width): if self.hidden[y][x]: result += "#" else: if self.board[y][x] == "X": result += "X" else: result += str(self.board[y][x]) result += "\n" return result def reveal(self, x, y): if self.hidden[y][x]: self.hidden[y][x] = False if self.board[y][x] == "X": self.game_over = True elif self.board[y][x] == 0: for dy in [-1, 0, 1]: for dx in [-1, 0, 1]: if dy == 0 and dx == 0: continue if 0 <= y + dy < self.height and 0 <= x + dx < self.width: self.reveal(x + dx, y + dy) def is_win(self): for y in range(self.height): for x in range(self.width): if self.board[y][x] != "X" and self.hidden[y][x]: return False return True # example usage game = Minesweeper(10, 10, 10) while not game.game_over and not game.is_win(): print(game) x = int(input("Enter x coordinate: ")) y = int(input("Enter y coordinate: ")) game.reveal(x, y) if game.game_over: print("Game over!") else: print("You win!") ``` 在这个示例代码中,我们定义了一个 `Minesweeper` 类来表示扫雷游戏。我们使用一个二维列表来表示游戏板,每个方块可以是一个数字(表示周围的地雷数量)或 "X"(表示这个方块是地雷)。我们还使用一个二维列表来表示哪些方块是隐藏的,哪些是已经被揭示的。我们使用一个列表来存储地雷的位置。 在 `__init__` 方法中,我们随机放置了一些地雷,并计算了每个方块周围的地雷数量。在 `__str__` 方法中,我们将游戏板和隐藏状态转换成一个字符串来展示给玩家。在 `reveal` 方法中,我们揭示了一个方块并递归揭示周围的方块,直到没有更多的空白方块为止。在 `is_win` 方法中,我们检查是否还有未揭示的非地雷方块,如果没有就说明玩家获胜了。 在示例代码的最后,我们创建了一个 `Minesweeper` 实例,并开始一个游戏循环,直到游戏结束或者玩家获胜。在每个循环中,我们展示当前游戏状态,等待玩家输入要揭示的方块的坐标,然后调用 `reveal` 方法来揭示方块。最后,我们检查游戏是否结束,并输出相应的提示信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值