栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

QT 扫雷程序介绍和开发(五)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

QT 扫雷程序介绍和开发(五)

扫雷目录

  • 目录

    扫雷目录

    前言

    一、扫雷程序应用截图

    二、使用步骤

    1.项目说明

    2.项目代码详解

    总结


前言

扫雷程序主要应用了C++开发语言和QT框架,其中应用了大量的UI部件已经事件处理等,代码包中给了大量的注释,方便小伙伴阅读和理解

一、QT扫雷程序应用展示

二、使用步骤

1.项目说明

项目代码流程图

 

2.项目代码详解

地图类主要用于创建生产地图

mine.h

#ifndef MINE_H
#define MINE_H


class Mine
{
public:
    Mine();

    
    bool GenerateMap(int in_raw, int in_column, int in_mineNum);

    
    void reGenerateMap();

    int getMineNumber();

    unsigned char **map;

private:
    int raw;//行数
    int column;//列数
    int mineNum;//雷数

    
    bool MallocMemForMap(int in_raw, int in_column, int in_mineNum);

    
    bool InitMap();

    
    void PrintMap();
};


#endif // MINE_H

 mine.cpp

#include "mine.h"
#include "stdlib.h"
#include 
#include 

using namespace std;

Mine::Mine()
{
    map = NULL;
}


bool Mine::GenerateMap(int in_raw, int in_column, int in_mineNum)
{
    if(false == MallocMemForMap(in_raw, in_column, in_mineNum))
    {
        cout << "error: malloc memory failed!" << endl;
        return false;
    }

    if(false == InitMap())
    {
        cout << "error: init map failed!" << endl;
        return false;
    }

    return true;
}

void Mine::reGenerateMap()
{
    InitMap();
}

int Mine::getMineNumber()
{
    return this->mineNum;
}



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 Mine::PrintMap()
{
    for(int i = 0; i < raw; i ++)
    {
        for(int j = 0; j < column; j ++)
        {
            cout << (int)map[i][j] << "t";
        }
        cout << endl;
    }
}

主界面主要创建界面UI,控制窗口事件

MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include "mine.h"
#include 

namespace Ui {
class MainWindow;
}


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    
    unsigned int defaultMap[3][3] = {{9,9,10},
                                     {16,16,40},
                                     {16,30,100}};

    
    bool ChangeLevel(int raw, int column, int mineNum);

    
    bool Restart();

    
    void paintEvent(QPaintEvent *);

    
    void mousePressEvent(QMouseEvent *event);

    
    bool MallocMemForMap_IsPushed(int in_raw, int in_column);

    
    void InitMap_IsPushed();

    
    bool GeneratePushedMap(int in_raw, int in_column);

    
    bool GenerateGlobalMap(int in_raw, int in_column, int in_mineNum);

    
    void changePosToIndex(int *px, int *py);

    void recursiveFreshBlock(int raw_pos, int col_pos);

    void pressLeftRightButtonPorc(int raw_pos, int col_pos);

    void pressLeftButtonProc(int raw_pos, int col_pos);

    void pressRightButtonProc(int raw_pos, int col_pos);

    //检查状态,标志置位处理
    void JudgeIsOver();

    Mine m;

    //地图方格的起始位置偏移
    int map_XOffset;
    int map_YOffset;

    //时间栏的起始位置偏移
    int time_XOffset;
    int time_YOffset;

    //初始状态均置为0
    struct StateFlag
    {
        bool IsOver;//游戏是否结束的状态,如果已经结束,置1,未结束置0。
        bool IsStart;//游戏是否开始的状态,如果已经开始,置1,未开始置0.
        bool result;//游戏结果,胜利置1,失败置0.
    }STATE_FLAG;


private slots:
    void on_actionExit_triggered();

    void on_actionprimary_triggered();

    void on_actionmedium_triggered();

    void on_actionexpert_triggered();

    void on_actionRestart_triggered();

    void on_timeChange();

    void on_actionVersion_triggered();

    void on_actionAuthor_triggered();

private:
    //上层地图标记,0---未点击过,1---点击过,2---插上了小旗
    int **map_flag;
    int raw;
    int column;

    //剩余雷的个数
    int mine_Left;

    //计时器
    QTimer *timer;
    int time_cost;


    Ui::MainWindow *ui;
};



#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 
#include 
#include 
#include 

using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //初始化各个成员变量。
    STATE_FLAG.IsOver = 0;
    STATE_FLAG.IsStart = 0;
    STATE_FLAG.result = 0;
    map_flag = NULL;
    map_XOffset = 5;
    map_YOffset = 64;
    time_XOffset = 0;
    time_YOffset = 27;

    this->time_cost = 0;
    this->timer = new QTimer(this);
    connect(this->timer,SIGNAL(timeout()),this,SLOT(on_timeChange()));

    
    setFixedSize(defaultMap[0][1] * 25 + map_XOffset * 2 , defaultMap[0][0] * 25 + map_YOffset + 5);
    GenerateGlobalMap(defaultMap[0][0],defaultMap[0][1],defaultMap[0][2]);
    
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::paintEvent(QPaintEvent *)
{
    QPixmap bmpblock;
    QPixmap bmpdigital;
    QPixmap bmpemoji;
    if(false == bmpblock.load("../src/block.bmp") || false == bmpdigital.load("../src/digital_32_25.bmp") || false == bmpemoji.load("../src/emoji.bmp"))
    {
        cout << "error:load bmp failed!" << endl;
    }
    else
    {
        cout << "info:load bmp success!" << endl;
    }
    QPainter painter(this);

    
    for(int i = 0; i < this->raw; i ++)
    {
        for(int j = 0; j < this->column; j ++)
        {
            //没有左击过的方格的绘制
            if(0 == map_flag[i][j])
            {
                painter.drawPixmap(j * 25 + map_XOffset, i * 25 + this->map_YOffset, bmpblock, 9 * 25, 0, 25, 25);
            }
            //左击过的方格绘制
            else if(1 == map_flag[i][j])
            {
                if(m.map[i][j] < 9)
                {
                    painter.drawPixmap(j * 25 + map_XOffset, i * 25 + this->map_YOffset, bmpblock, m.map[i][j] * 25, 0, 25, 25);
                }

                else if(m.map[i][j] == '*')
                {
                    painter.drawPixmap(j * 25 + map_XOffset, i * 25 + this->map_YOffset, bmpblock, 11 * 25, 0, 25, 25);
                }
            }
            //插小旗的绘制
            else if(2 == map_flag[i][j])
            {
                painter.drawPixmap(j * 25 + map_XOffset, i * 25 + this->map_YOffset, bmpblock, 12 * 25, 0, 25, 25);
            }
            //插错旗:3
            else
            {
                painter.drawPixmap(j * 25 + map_XOffset, i * 25 + this->map_YOffset, bmpblock, 13 * 25, 0, 25, 25);
            }
        }
    }



    //游戏已结束
    if(1 == STATE_FLAG.IsOver)
    {
        //游戏失败,所有未翻开的雷全部翻开
        if(0 == STATE_FLAG.result)
        {
            for(int i = 0; i < this->raw; i ++)
            {
                for(int j = 0; j < this->column; j ++)
                {
                    if(0 == map_flag[i][j] && m.map[i][j] == '*')
                    {
                        painter.drawPixmap(j * 25 + map_XOffset, i * 25 + this->map_YOffset, bmpblock, 10 * 25, 0, 25, 25);
                    }
                }
            }
            // 表情切换为哭
            painter.drawPixmap((this->column * 25 + 2 * map_XOffset) / 2 - 15, this->time_YOffset, bmpemoji, 2 * 31, 0, 31, 31);

        }
        //游戏胜利,切换表情,点击锁定
        else
        {
            painter.drawPixmap((this->column * 25 + 2 * map_XOffset) / 2 - 15, this->time_YOffset, bmpemoji, 1 * 31, 0, 31, 31);
        }

    }
    else
    {
        painter.drawPixmap((this->column * 25 + 2 * map_XOffset) / 2 - 15, this->time_YOffset, bmpemoji, 0, 0, 31, 31);
    }
    

    
    int gtemp,stemp,btemp,mine_leftTemp;
    mine_leftTemp = mine_Left < 1 ? 0 : mine_Left;
    btemp = mine_leftTemp / 100;
    stemp = mine_leftTemp / 10 - btemp * 10;
    gtemp = mine_leftTemp - btemp * 100 - stemp * 10;
    cout << "mineLeftNum: " << this->mine_Left << "  btemp: " << btemp << "  stemp: " << stemp << "  gtemp:" << gtemp << endl;
    painter.drawPixmap(0 + map_XOffset, this->time_YOffset, bmpdigital, btemp * 25, 0, 25, 32);
    painter.drawPixmap(25 + map_XOffset, this->time_YOffset, bmpdigital, stemp * 25, 0, 25, 32);
    painter.drawPixmap(50 + map_XOffset, this->time_YOffset, bmpdigital, gtemp * 25, 0, 25, 32);
    

    
    int time_temp = this->time_cost;
    btemp = time_temp / 100;
    stemp = time_temp / 10 - btemp * 10;
    gtemp = time_temp - btemp * 100 - stemp * 10;
    cout << "timecost: " << this->time_cost << "  btemp: " << btemp << "  stemp: " << stemp << "  gtemp:" << gtemp << endl;
    painter.drawPixmap(this->column * 25 + map_XOffset - 75, this->time_YOffset, bmpdigital, btemp * 25, 0, 25, 32);
    painter.drawPixmap(this->column * 25 + map_XOffset - 50, this->time_YOffset, bmpdigital, stemp * 25, 0, 25, 32);
    painter.drawPixmap(this->column * 25 + map_XOffset - 25, this->time_YOffset, bmpdigital, gtemp * 25, 0, 25, 32);
    
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    int ppx = event->x();
    int ppy = event->y();
    cout << "ppx: " << ppx << "  ppy: " << ppy << endl;
    cout << "xArea: " << map_XOffset << "," << 25 * this->column + map_XOffset << endl;
    cout << "yArea: " << map_YOffset << "," << 25 * this->raw + map_YOffset << endl;
    //如果点击位置不在方格区域内,点击表情进行处理,否则不处理
    if(!((ppx > map_XOffset && ppx < 25 * this->column + map_XOffset) && (ppy > map_YOffset && ppy < this->raw * 25 + map_YOffset)))
    {
        int temp_x = (this->column * 25 + 2 * map_XOffset) / 2 - 15;
        int temp_y = this->time_YOffset;
        if(ppx >= temp_x && ppx <= temp_x + 31 && ppy >= temp_y && ppy <= temp_y + 31)
        {
            on_actionRestart_triggered();
        }
        //cout << "error: not in the correct area!" << endl;
        return;
    }
    //如果游戏处于结束状态,不响应点击事件
    if(1 == STATE_FLAG.IsOver)
    {
        return;
    }
    changePosToIndex(&ppx, &ppy);
    if((Qt::LeftButton|Qt::RightButton) == event->buttons())
    {
        //如果游戏还没有开始,不响应左右双击事件
        if(0 == STATE_FLAG.IsStart)
        {
            return;
        }
        pressLeftRightButtonPorc(ppy, ppx);
    }
    else if(Qt::LeftButton == event->button())
    {
        if(0 == STATE_FLAG.IsStart)
        {
            STATE_FLAG.IsStart = 1;
            this->timer->start(1000);
        }
        pressLeftButtonProc(ppy, ppx);
    }
    else if(Qt::RightButton == event->button())
    {
        pressRightButtonProc(ppy, ppx);
    }

    //更新游戏状态
    JudgeIsOver();
    update();

}

bool MainWindow::MallocMemForMap_IsPushed(int in_raw, int in_column)
{
    if(1 > in_raw || 1 > in_column)
    {
        cout << "error: malloc mem for map_IsPushed failed !" << endl;
        return false;
    }
    if(NULL != map_flag)
    {
        for(int i = 0; i < raw ;i ++)
        {
            delete map_flag[i];
        }
        delete map_flag;
        map_flag = NULL;
    }

    raw = in_raw;
    column = in_column;

    map_flag = new int*[raw];
    for(int j = 0; j < raw; j ++)
    {
        map_flag[j] = new int[column];
    }

    return true;
}

void MainWindow::InitMap_IsPushed()
{
    for(int i = 0 ;i < raw ;i ++)
    {
        for(int j = 0; j < column; j ++)
        {
            map_flag[i][j] = 0;
        }
    }
}

bool MainWindow::GeneratePushedMap(int in_raw, int in_column)
{
    if(false == MallocMemForMap_IsPushed(in_raw, in_column))
    {
        cout << "error: malloc mem for map_IsPushed failed!!" << endl;
        return false;
    }

    InitMap_IsPushed();
    return true;
}

void MainWindow::changePosToIndex(int *px, int *py)
{
    //进入此函数,由外部调用保证点击区域为方块区域
    *px = (*px - map_XOffset) / 25;
    *py = (*py - map_YOffset) / 25;
}

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

void MainWindow::pressLeftRightButtonPorc(int raw_pos, int col_pos)
{
    //先统计周围一圈的小旗个数,比较是否和此块数值相同
    int cnt = 0;
    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;

    for(int i = raw_s; i <= raw_e;i ++)
    {
        for(int j = col_s; j <= col_e; j ++)
        {
            if(2 == map_flag[i][j])
            {
                cnt ++;
            }
        }
    }

    if(cnt != m.map[raw_pos][col_pos])
    {
        return;
    }
    else
    {
        for(int i = raw_s; i <= raw_e;i ++)
        {
            for(int j = col_s; j <= col_e; j ++)
            {
                switch(map_flag[i][j])
                {
                case 2:
                    if('*' != m.map[i][j])
                    {
                        map_flag[i][j] = 3;
                    }
                    break;
                case 0:
                    pressLeftButtonProc(i, j);
                    break;
                default:
                    break;
                }
            }
        }
    }
}

void MainWindow::pressLeftButtonProc(int raw_pos, int col_pos)
{
    if(1 == map_flag[raw_pos][col_pos] || 2 == map_flag[raw_pos][col_pos])
    {
        //已经点击的区域或已插上红旗的区域,不需要处理
        return;
    }
    map_flag[raw_pos][col_pos] = 1;
    if(0 == m.map[raw_pos][col_pos])
    {
        recursiveFreshBlock(raw_pos, col_pos);
    }
}

void MainWindow::pressRightButtonProc(int raw_pos, int col_pos)
{
    switch (map_flag[raw_pos][col_pos])
    {
    case 1:
        return;
    case 2:
        map_flag[raw_pos][col_pos] = 0;
        this->mine_Left ++;
        break;
    case 0:
        map_flag[raw_pos][col_pos] = 2;
        this->mine_Left --;
        break;
    default:
        break;
    }
}

void MainWindow::JudgeIsOver()
{
    bool tempflag = 1;
    for(int i = 0; i < this->raw; i ++)
    {
        for(int j = 0; j < this->column; j ++)
        {
            //如果点击到雷,游戏结束,结果判负
            if(1 == map_flag[i][j] && '*' == m.map[i][j])
            {
                STATE_FLAG.IsOver = 1;
                STATE_FLAG.result = 0;
                this->timer->stop();
                return;
            }
            //如果有非雷非0的区域没有被点击,游戏没有结束,继续检查。
            if('*' != m.map[i][j] && 0 != m.map[i][j] && 0 == map_flag[i][j])
            {
                tempflag = 0;
            }
        }
    }
    if(tempflag)
    {
        //所有非雷非0格子都被点过,游戏结束,结果判胜
        STATE_FLAG.IsOver = 1;
        STATE_FLAG.result = 1;
        this->timer->stop();
    }
}

bool MainWindow::GenerateGlobalMap(int in_raw, int in_column, int in_mineNum)
{
    mine_Left = in_mineNum;
    //生成一层地图
    if(false == m.GenerateMap(in_raw,in_column,in_mineNum))
    {
        cout << "error: generate map failed !!" << endl;
        return false;
    }
    //生成二层地图
    if(false == GeneratePushedMap(in_raw, in_column))
    {
        cout << "error: generate pushed map failed!!" << endl;
        return false;
    }
    return true;
}

bool MainWindow::ChangeLevel(int in_raw, int in_column, int in_mineNum)
{
    STATE_FLAG.IsOver = 0;
    STATE_FLAG.IsStart = 0;
    setFixedSize(in_column * 25 + map_XOffset * 2 , in_raw * 25 + map_YOffset + 5);
    this->time_cost = 0;
    this->timer->stop();
    GenerateGlobalMap(in_raw, in_column, in_mineNum);
    update();
    return true;
}

void MainWindow::on_actionExit_triggered()
{
    exit(0);
}

void MainWindow::on_actionprimary_triggered()
{
    ChangeLevel(defaultMap[0][0], defaultMap[0][1], defaultMap[0][2]);
}

void MainWindow::on_actionmedium_triggered()
{
    ChangeLevel(defaultMap[1][0], defaultMap[1][1], defaultMap[1][2]);
}

void MainWindow::on_actionexpert_triggered()
{
    ChangeLevel(defaultMap[2][0], defaultMap[2][1], defaultMap[2][2]);
}

void MainWindow::on_actionRestart_triggered()
{
    STATE_FLAG.IsOver= 0;
    STATE_FLAG.IsStart = 0;
    setFixedSize(column * 25 + map_XOffset * 2 , raw * 25 + map_YOffset + 5);
    this->mine_Left = m.getMineNumber();
    this->time_cost = 0;
    this->timer->stop();
    m.reGenerateMap();
    InitMap_IsPushed();
    update();
}

void MainWindow::on_timeChange()
{
    this->time_cost ++;
    cout << "@@time: " << this->time_cost << endl;
    update();

}

void MainWindow::on_actionVersion_triggered()
{
    QString title = "Version";
    QString content = "Version:1.0n基本功能开发完成ntttt2018.04.11";
    QMessageBox::information(NULL, title, content, QMessageBox::Ok);
}

void MainWindow::on_actionAuthor_triggered()
{
    QString title = "Author";
    QString content = "t这款扫雷是学习了一份扫雷开源代码后做的个人小练习,之后会在此基础上增加更多的扩展内容~欢迎各位同道中人交流联系~     ---不定期更新nnEmail:heqi_dlmuit@163.comnQQ:292931255";
    QMessageBox::information(NULL, title, content, QMessageBox::Ok);
}

总结

本项目主要用了C++和QT框架进行开发,对代码能力有一定的要求,小伙伴们可以把代码导入到自己的项目中进行开发和使用,还可以作为代码参考。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/968868.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号