1. 程式人生 > >C++ 掃雷遊戲實現

C++ 掃雷遊戲實現

C++ 掃雷遊戲
這個星期在嘗試著自己寫一個掃雷遊戲。功能基本和windows下的功能差不多。左鍵單擊翻開一個格子,如果沒有雷則顯示其周圍格子中含有雷的個數,沒有周圍的沒有雷的話,那麼就擴充套件空白塊。
擴充套件空白塊的步驟為:1、翻開一個格子,如果檢測有雷,則退出遊戲;2、如果檢測沒有雷,那麼就檢測其周圍的八個格子,如果周圍有雷的話,顯示含有雷的個數,跳到第四步;3、沒有周圍都沒有雷的話,翻開這個格子,並且對周圍的八個格子重複第二步。4、進行下一次滑鼠點選檢測。
掃雷遊戲的難點在於如何擴充套件空白塊和捕捉到滑鼠的點選操作。
捕捉滑鼠的點選操作:注意在控制檯視窗中,直接執行這個程式是不能捕捉到滑鼠的點選操作的,需要在開啟的那個控制檯視窗上面那個白色邊框,右鍵滑鼠選擇屬性,然後關閉快速編輯選項,之後就可以正常的捕捉到滑鼠的點選操作了。

  HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
        HANDLE  hin = GetStdHandle(STD_INPUT_HANDLE);
        COORD coord, pos;
        INPUT_RECORD mouseRec;
        DWORD res;
        ReadConsoleInput(hin, &mouseRec, 1, &res);                                         //該函式用於讀取滑鼠和鍵盤事件
        if
(mouseRec.EventType == MOUSE_EVENT) //檢查是否有滑鼠的按鍵按下 { cout << "滑鼠" << endl; if (mouseRec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) //最左邊的按鍵按下 { cout << "左" << endl; } if
(mouseRec.Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED) //最右邊的按鍵按下 { cout << "右" << endl; cout << "|>"; } }

空白塊的擴充套件:一般有兩種方法遞迴和有一個標誌陣列。我採用的是遞迴實現的。

/*用於檢測各點座標點周圍的八個格子種地雷的個數*/

int detect_sweeper_eight(int a, int b, int init_p[], vector<vector<int>> map_sweeper)
{
    int temp_sweeper_count = 0;

    for (int i = a - 1; i < a + 2; ++i)                      //統計點開的格子周圍的地雷的個數
    for (int j = b - 1; j < b + 2; ++j)                     //檢測雷區這一塊還需要進行相應的更改
    {
        if (i<0 || j<0 || i>init_p[0] - 1 || j>init_p[1] - 1)
        {
            temp_sweeper_count = temp_sweeper_count;
        }
        else
        {
            if (map_sweeper[i][j] == 1)
                temp_sweeper_count++;
        }
    }

    return temp_sweeper_count;
}



/* 這個遊戲中需要對已經翻開的格子進行做了標記,這個是重點,
第一次因為沒有對已經翻開的格子進行標記,導致程式進入了死迴圈;
第二次加入了標記,能夠正確的擴充套件空白塊,但是一直在空白塊之間迴圈,
後來發現是那個用來標識地雷的陣列沒有進行引用傳遞。用的是值傳遞的方式,這樣導致了無限迴圈,但是程式不會退出*/


void detect_sweeper(int a, int b, int init_p[], vector<vector<int>> map_sweeper, vector<vector<int>> &map_sweeper_flag)
{
    int sweeper_count = 0;
    int map_a = a + init_p[2];
    int map_b = b + init_p[3];
    sweeper_count = detect_sweeper_eight(a, b, init_p, map_sweeper);
    if (!sweeper_count)                                                                   //如果點開的格子周圍都沒有地雷的話,那麼就把這九個空格給消去 
    {
        locate(map_b, map_a);
        cout << " ";
        map_sweeper_flag[a][b] = 0;
        for (int i = a - 1; i < a + 2; ++i)
        for (int j = b - 1; j < b + 2; ++j)
        {
            if ((i == a && j == b) || i<0 || j<0 || i>init_p[0] - 1 || j>init_p[1] - 1) //是中心點、到達邊界
            {
            } 
            else
            {
                if (map_sweeper_flag[i][j] == 0){}                                      //已經翻開的格子進行做了標記,這個是重點,之前不會退出迴圈,後來發現是那個用來標識地雷的陣列沒有進行引用傳遞。
                else                                                                    //用的是值傳遞的方式,這樣導致了無限迴圈
                {
                    detect_sweeper(i, j, init_p, map_sweeper, map_sweeper_flag);

                }
            }

        }
    }
    else
    {
        locate(map_b, map_a);
        cout << sweeper_count;
        map_sweeper_flag[a][b] = 0;
    }


}

掃雷遊戲最主要的就是這兩個部分了。下面是結果截圖:
初始化地圖
最終結果圖