扫雷(Qt版本) 简单类封装

学习Qt/C++
实现扫雷小游戏
扫雷(Qt版本) 简单类封装_第1张图片

扫雷的规则原理可以参考我用python写的
https://blog.csdn.net/boonion/article/details/130004569

下面直接提供基于Qt的扫雷完整源码

封装扫雷创建的头文件以及源码cpp
qminesweeper.h:

#ifndef QMINESWEEPER_H
#define QMINESWEEPER_H

#include 
#include 
#include 
#include 


//方块状态码
#define BLOCK_STATE_AREA    0       //未打开
#define BLOCK_STATE_OPENED  1       //已打开
#define BLOCK_STATE_FLAG    2       //被标记
#define BLOCK_STATE_DOUBT   3       //被怀疑
#define BLOCK_STATE_BOOM    4       //被引爆
#define BLOCK_STATE_SWEEPED 5       //被扫除
#define BLOCK_STATE_MISTAKE 6       //标记错误

//游戏状态信号码
#define GAME_STATE_SWEEP        0   //有方块被扫除
#define GAME_STATE_SUCCESSFUL   1   //所有方块被扫除游戏通过
#define GAME_STATE_DEFEATED     2   //游戏结束
#define GAME_SET_FLAG           3   //有方块被标记
#define GAME_RESET_FLAG         4   //有方块被取消标志


typedef QPushButton QBlock;


class QMineSweeper : public QBlock
{
    Q_OBJECT
public:
    explicit QMineSweeper(int id,QWidget *parent = nullptr);

    static void createMap(QWidget *w = mainWindow ,int row = mapRow ,int col = mapCol,int mine = mineNum , int x0 = mapX0, int y0 = mapY0 ,int mine_size = mineSize);
    static void setMapSize(int row,int col){mapRow = row; mapCol = col;}
    static void setMapXY0(int x0 ,int y0){mapX0 = x0 ; mapY0 = y0;}
    static void setMineNum(int num){mineNum = num;}
    static void setMineSize(int size){mineSize = size;}
    static void setMainWindow(QWidget *w){mainWindow = w;}
    static void initMap();
    static QMineSweeper *getEventMine(){return eventMine;}//eventMine方块将所有的方块信号进行转发
private:
    //地图与地雷尺寸
    static QMap<int,QMineSweeper *> mineMap;
    static int mapRow;
    static int mapCol;
    static int mineNum;
    static int mineSize;
    static int gameState;
    static int mapX0;
    static int mapY0;
    static int openCount;//方块被打开的数量统计
    static QString numColorStyle[10];//0~9的颜色状态样式列表
    static QString numStateStyle[7];//方块状态码对应的样式列表
    static QWidget *mainWindow;     //主窗口
    static QMineSweeper *eventMine; //用于转发所有事件的方块


signals:
    void mineSweeperGameOver(int state);//发送游戏状态的信号
private slots:
    void transponder(int state);//eventMine方块将所有的方块信号转发

private:
    void setSelfN(int n){selfN = n;}
    int  getSelfN(){return selfN;}
    void openBlock();
    void updateStyle();

public:

protected:
    virtual void mousePressEvent(QMouseEvent *event);


private:

    int selfid;     //方块唯一标识id
    int selfN;      //危险数值
    int selfState;
    QList<int> neighbors;

};

#endif // QMINESWEEPER_H

qminesweeper.cpp:

#include "qminesweeper.h"

#include 
#include 
#include 

QMap<int,QMineSweeper *> QMineSweeper::mineMap;
QWidget * QMineSweeper::mainWindow = nullptr;
QMineSweeper * QMineSweeper::eventMine = nullptr;
QString QMineSweeper::numColorStyle[10];
QString QMineSweeper::numStateStyle[7];

int QMineSweeper::mapRow = 6;
int QMineSweeper::mapCol = 5;
int QMineSweeper::mineNum = 3;
int QMineSweeper::mineSize = 30;
int QMineSweeper::gameState = GAME_STATE_SWEEP;
int QMineSweeper::mapX0 = 30;
int QMineSweeper::mapY0 = 30;
int QMineSweeper::openCount = 0;

void myrand(int n,int min,int max,QList<int> &list);

QMineSweeper::QMineSweeper(int id,QWidget *parent) : QBlock(parent)
{
    selfid = id;
    selfN = 0;
    selfState = BLOCK_STATE_AREA;
    mineMap.insert(id,this);
    updateStyle();

    if(eventMine == nullptr)
        eventMine = this;

   connect(this,SIGNAL(mineSweeperGameOver(int)),eventMine,SLOT(transponder(int)));
}

void QMineSweeper::createMap(QWidget *w, int row, int col, int mine, int x0, int y0, int mine_size)
{

    mainWindow = w;
    mapRow = row;
    mapCol = col;
    mineNum = mine;
    mapX0 = x0;
    mapY0 = y0;
    mineSize = mine_size;
    gameState = GAME_STATE_SWEEP;
    openCount = 0;
    eventMine = nullptr;

    numColorStyle[0] = "";
    numColorStyle[1] = "color: rgb(9, 147, 62);";
    numColorStyle[2] = "color: rgb(0, 187, 187);";
    numColorStyle[3] = "color: rgb(240, 78, 0);";
    numColorStyle[4] = "color: rgb(166, 19, 188);";
    numColorStyle[5] = "color: rgb(185, 122, 87);";
    numColorStyle[6] = "color: rgb(136, 0, 21);";
    numColorStyle[7] = "color: rgb(163, 73, 164);";
    numColorStyle[8] = "color: rgb(0, 0, 0);";
    numColorStyle[9] = "";

    numStateStyle[0] = "background-color: rgb(144, 144, 144);";
    numStateStyle[1] = "background-color: rgb(211, 211, 211);";
    numStateStyle[2] = "background-color: rgb(130, 255, 150);";
    numStateStyle[3] = "background-color: rgb(77, 166, 255);";
    numStateStyle[4] = "background-color: rgb(255, 0, 0);";
    numStateStyle[5] = "background-color: rgb(0, 170, 0);";
    numStateStyle[6] = "background-color: rgb(0, 170, 0);";


    initMap();

}

void QMineSweeper::initMap()
{
    qDeleteAll(mineMap);
    mineMap.clear();

    //生成雷方块的id列表
    QList<int> id_list;
    myrand(mineNum,0,mapRow * mapCol,id_list);

    for(int i = 0 ; i < mapRow * mapCol ; i++)
    {
            int id = i;
            QMineSweeper *block = new QMineSweeper(id,mainWindow);

            int r = i / mapCol;
            int c = i % mapCol;

            //如果该方块id在雷方块id列表内则赋值为雷(9)
            if(id_list.contains(id))
                block->setSelfN(9);

            //生成相邻方块的id列表
            for(int i_r = -1 ; i_r < 2 ; i_r ++)
                for(int i_c = -1 ; i_c < 2 ; i_c++)
                {
                    int nid = id + i_r * mapCol + i_c;
                    if(i_r+r>=0&&i_r+r<mapRow&&i_c+c>=0&&i_c+c<mapCol&&nid!=id)
                        block->neighbors.append(nid);
                }

            block->setGeometry(c*mineSize+mapX0,r*mineSize+mapY0,mineSize,mineSize);
            block->show();
    }

    //为雷方块相邻的方块映射雷区
    foreach(int mid, id_list)
    {
        foreach(int nid , mineMap[mid]->neighbors)
        {

            int n = mineMap[nid]->getSelfN();
            //n不为9表明为雷区,危险数值加一
            if(n != 9)
                mineMap[nid]->setSelfN(n+1);
        }

    }
}

void QMineSweeper::transponder(int state)
{
    QMineSweeper *sender_p = qobject_cast<QMineSweeper *>(sender());

    //若信号发出者不是自身则转发事件信号
    if(sender_p != eventMine)
        emit mineSweeperGameOver(state);

}

void QMineSweeper::openBlock()
{
    if(selfState == BLOCK_STATE_OPENED)
        return;
    if(selfN == 9)
    {
        gameState = GAME_STATE_DEFEATED;
        selfState = BLOCK_STATE_BOOM;
        updateStyle();
        emit mineSweeperGameOver(gameState);
        return;
    }

    selfState = BLOCK_STATE_OPENED;
    openCount++;
    updateStyle();

    emit mineSweeperGameOver(GAME_STATE_SWEEP);

    if(openCount >= mapRow*mapCol - mineNum)
    {
        gameState = GAME_STATE_SUCCESSFUL;
        emit mineSweeperGameOver(gameState);
        return;
    }

    if(selfN == 0)
    {
        foreach(int id , neighbors)
            mineMap[id]->openBlock();
    }

}

#include 

void QMineSweeper::updateStyle()
{
    if(selfN != 0 && selfN !=9 && selfState == BLOCK_STATE_OPENED)
        this->setText(QString("%1").arg(selfN));
    else
         this->setText(QString(" "));



    setStyleSheet(numStateStyle[selfState]+numColorStyle[selfN]);
    this->update();
}

void QMineSweeper::mousePressEvent(QMouseEvent *event)
{
    if(gameState != GAME_STATE_SWEEP)
        return;

    if(event->button() == Qt::RightButton)
    {
        if(selfState == BLOCK_STATE_OPENED)
            return;
        else if(selfState == BLOCK_STATE_AREA)
        {
            selfState = BLOCK_STATE_FLAG;
           emit mineSweeperGameOver(GAME_SET_FLAG);
        }
        else if(selfState == BLOCK_STATE_FLAG)
        {
            selfState = BLOCK_STATE_DOUBT;
            emit mineSweeperGameOver(GAME_RESET_FLAG);
        }
        else if(selfState == BLOCK_STATE_DOUBT)
        {
            selfState = BLOCK_STATE_AREA;
        }
        updateStyle();

    }
    else if(event->button() == Qt::LeftButton)
    {
        openBlock();

    }
}



void myrand(int n,int min,int max,QList<int> &list)
{
    QMap<int,bool> maps;

    qsrand((uint)QDateTime::currentMSecsSinceEpoch());

    for(int i = 0 ; i < n && i < max - min; i++)
    {
        int r_count = qrand()%(max-min)+min;
        while(maps[r_count] == true)
            r_count = qrand()%(max-min)+min;

        maps[r_count] = true;
        list.append(r_count);

    }
}


窗口操作显示等

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void gameOption();
    void customOption();
    void gameState(int state);
private:
    void initMenu();

    QLabel *msgLabel;
};

#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "qminesweeper.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    resize(200,250);

    msgLabel = new QLabel(this);
    msgLabel->hide();

    QMineSweeper::createMap(this);
    connect(QMineSweeper::getEventMine(),SIGNAL(mineSweeperGameOver(int)),
            this,SLOT(gameState(int)));
    initMenu();

}

MainWindow::~MainWindow()
{

}

void MainWindow::gameOption()
{
    QObject *option = qobject_cast<QObject *>(sender());
    QString objectname = option->objectName();

    if(objectname.contains("gameOption:"))
    {
        QStringList list= objectname.split(":");
        int r = list.at(1).toInt();
        int c = list.at(2).toInt();
        int mine = list.at(3).toInt();
        int minSize = 30;
        int x0 = 30;
        int y0 = 30;
        QMineSweeper::createMap(this,r,c,mine);
        connect(QMineSweeper::getEventMine(),SIGNAL(mineSweeperGameOver(int)),
                this,SLOT(gameState(int)));
        resize((c+1)*minSize+x0,(r+1)*minSize+y0);
        msgLabel->hide();
    }


}

void MainWindow::customOption()
{
    QGridLayout* gLayout = new QGridLayout;
    QDialog *dialog = new QDialog(this);

    QPushButton* pButton1 = new QPushButton(QString("确定"));
    QPushButton* pButton2 = new QPushButton(QString("取消"));
    pButton1->setFixedSize(50,30);
    pButton2->setFixedSize(50,30);
    QLabel* labe1 = new QLabel("行数:",dialog);
    QLabel* labe2 = new QLabel("列数:",dialog);
    QLabel* labe3 = new QLabel("雷数:",dialog);


    QLineEdit* edit1 = new QLineEdit(dialog);
    edit1->setPlaceholderText("输入地图的行数R");
    QLineEdit* edit2 = new QLineEdit(dialog);
    edit2->setPlaceholderText("输入地图的列数C");
    QLineEdit* edit3 = new QLineEdit(dialog);
    edit3->setPlaceholderText("输入雷的个数num);


    gLayout->addWidget(labe1,0,0);
    gLayout->addWidget(labe2,1,0);
    gLayout->addWidget(labe3,2,0,1,1);
    gLayout->addWidget(edit1,0,1,1,4);
    gLayout->addWidget(edit2,1,1,1,4);
    gLayout->addWidget(edit3,2,1,1,4);
    gLayout->addWidget(pButton1,3,1);
    gLayout->addWidget(pButton2,3,4);


    connect(pButton1,SIGNAL(clicked()),dialog,SLOT(accept()));
    connect(pButton2,SIGNAL(clicked()),dialog,SLOT(reject()));

    dialog->setWindowTitle("自定义");
    dialog->setMinimumSize(200,50);
    dialog->setWindowFlag(Qt::Dialog);
    dialog->setLayout(gLayout);

    if(QDialog::Accepted == dialog->exec())
    {
        int r = edit1->text().toInt();
        int c = edit2->text().toInt();
        int num = edit3->text().toInt();
        int minSize = 30;
        int x0 = 30;
        int y0 = 30;

        if(num > r*c)
            return;

        QMineSweeper::createMap(this,r,c,num,x0,y0,minSize);
        connect(QMineSweeper::getEventMine(),SIGNAL(mineSweeperGameOver(int)),
                this,SLOT(gameState(int)));

        resize((c+1)*minSize+x0,(r+1)*minSize+y0);
        msgLabel->hide();
    }
}

void MainWindow::gameState(int state)
{
    QString msg;

    if(state == GAME_STATE_SUCCESSFUL)
        msg = "恭喜通过!";
    else if(state == GAME_STATE_DEFEATED)
        msg = "游戏结束!";

    if(!msg.isEmpty())
    {
        msgLabel->setText(msg);
        msgLabel->setGeometry(100,100,100,20);
        msgLabel->raise();
        msgLabel->show();
    }
}

void MainWindow::initMenu()
{

    QMenuBar *bar = this->menuBar();
    QMenu *gameMenu = bar->addMenu("游戏");

    QAction *act = gameMenu->addAction("入门");
    act->setObjectName("gameOption:6:5:3");
    connect(act,SIGNAL(triggered()),this,SLOT(gameOption()));

    act = gameMenu->addAction("简单");
    act->setObjectName("gameOption:10:10:15");
    connect(act,SIGNAL(triggered()),this,SLOT(gameOption()));

    act = gameMenu->addAction("一般");
    act->setObjectName("gameOption:16:16:40");
    connect(act,SIGNAL(triggered()),this,SLOT(gameOption()));

    act = gameMenu->addAction("困难");
    act->setObjectName("gameOption:15:20:60");
    connect(act,SIGNAL(triggered()),this,SLOT(gameOption()));

    act = gameMenu->addAction("自定义");
    connect(act,SIGNAL(triggered()),this,SLOT(customOption()));

}

使用qt创建一个无UI的主窗口类App模板,复制以上代码粘贴到对应文件上面,运行试试便可以

你可能感兴趣的:(Qt,qt,c++,开发语言)