基于Qt的扫雷游戏(附源码)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_25453065/article/details/79827715

基于Qt的扫雷游戏(附源码)

本人码农一枚,平日工作涉及面太窄,写代码也没有根据自己想法写来的开心。故周末挤出闲碎时间做些简单的内容来保持手感,先挑了个比较简单的扫雷游戏作为日后漫长之路的起步。此代码在github上开源,文末附有地址。

目录

核心算法

扫雷游戏实现很简单,核心内容包括生成随机地图 & 递归翻开格子。其他内容基本都是些简单的逻辑,这里不谈及。

生成随机地图

原理:定义一个全局的二维数组指针,每次生成地图,需要经过释放内存,申请内存,初始化内存,生成地雷随机坐标,填数字的过程。随机生成每个雷的x,y坐标,随机因子每次根据当时时间来设置以保证其随机性。

bool Mine::MallocMemForMap(int in_raw, int in_column, int in_mineNum)
{
    //非法入参
    if(1 > in_raw || 1 > in_column || 1 > in_mineNum || in_mineNum > in_raw * in_column)
    {
        cout << "error: para error!" << endl;
        return false;
    }
    if(NULL != map)
    {
        for(int i = 0; i < raw; i ++)
        {
            delete map[i];
        }
        delete map;
    }
    map = NULL;

    raw = in_raw;
    column = in_column;
    mineNum = in_mineNum;

    map = new unsigned char*[raw];
    for(unsigned char j = 0; j < raw; j ++)
    {
        map[j] = new unsigned char[column];
    }
    return true;
}



bool Mine::InitMap()
{
    int xpos, ypos, mineLeft = mineNum;
    int xs, xe, ys, ye;//填值时使用的上下左右边界值

    if(NULL == map)
    {
        cout << "error: null ptr!" << endl;
        return false;
    }
    //初始化内存,全部填0
    for(int i = 0; i < raw; i ++)
    {
        for(int j = 0; j < column; j ++)
        {
            map[i][j] = 0;
        }
    }

    //埋雷---采用随机生成雷坐标的方式,雷使用符号'*'的ASCII
    srand(time(NULL));//以当前时间为随机种子,保证随机性
    while(0 != mineLeft)
    {
        xpos = rand() % raw;
        ypos = rand() % column;
        if(0 == map[xpos][ypos])
        {
            map[xpos][ypos] = '*';
            mineLeft --;
        }
        continue;
    }

    //根据雷的分布填充其他方格数值
    for(int i = 0; i < raw; i ++)
    {
        for(int j = 0; j < column; j ++)
        {
            if('*' == map[i][j])
            {
                //设定雷周围可遍历方格的区间
                xs = (i - 1 >= 0) ? (i - 1) : i;
                xe = (i + 1 < raw) ? (i + 1) : i;
                ys = (j - 1 >= 0) ? (j - 1) : j;
                ye = (j + 1 < column) ? (j + 1) : j;

                for(xpos = xs; xpos <= xe ; xpos ++)
                {
                    for(int ypos = ys; ypos <= ye; ypos ++)
                    {
                        if('*' == map[xpos][ypos])
                        {
                            continue;
                        }
                        map[xpos][ypos] ++;
                    }
                }
            }
        }
    }
    return true;
}

###递归翻开格子
当点击的方块是空格子时,需要向四周递归直到找到四周是数字边界或者地图边界为止。

void MainWindow::recursiveFreshBlock(int raw_pos, int col_pos)
{
    int raw_s, raw_e, col_s, col_e;//上下左右边界值
    //设定周围可遍历方格的区间
    raw_s = (raw_pos - 1 >= 0) ? (raw_pos - 1) : raw_pos;
    raw_e = (raw_pos + 1 < raw) ? (raw_pos + 1) : raw_pos;
    col_s = (col_pos - 1 >= 0) ? (col_pos - 1) : col_pos;
    col_e = (col_pos + 1 < column) ? (col_pos + 1) : col_pos;

    map_flag[raw_pos][col_pos] = 1;

    for(int i = raw_s; i <= raw_e; i ++)
    {
        for(int j = col_s; j <= col_e; j ++)
        {
            if(i == raw_pos && j == col_pos)
            {
                continue;
            }
            if(0 == m.map[i][j] && 0 == map_flag[i][j])
            {
                recursiveFreshBlock(i, j);
            }
            else
            {
                map_flag[i][j] = 1;
            }
        }
    }
}

UI素材

动手PS的一些素材
格子素材
用于显示时间和剩余雷数
表示当前游戏状态的表情

源码链接

github持续更新
https://github.com/qmeng0207/mine_sweeping



2018.04.05 更新



加班加的好久没动手了,为了拓展练习,决定按照以下步骤改进功能。
1.局域网内联机对战,一台做server,一台做clinet即可。
2.刚好租了搬瓦工的服务器一台,打算把server迁移到服务器端
3.手写一个扫雷AI,部署到服务器上(其实算不上AI),只是想把自己分析扫雷的思路凝聚一下。
4.增加一个可以自由设计地图的功能,自由摆雷。设计好的地图可以以二进制文件形式进行存储,随时加载使用。目的是为了设计一些有趣的地图形状。
。。。

第一个在进行中,完成后更新github。



2018.09.22更新

展开阅读全文

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