扫雷的规则原理可以参考我用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模板,复制以上代码粘贴到对应文件上面,运行试试便可以