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;
    }


}

扫雷游戏最主要的就是这两个部分了。下面是结果截图:
初始化地图
最终结果图

没有更多推荐了,返回首页