先看效果:
- 利用QT搭建迷宫界面
- 利用单选框来构造迷宫,设置障碍物和宝藏的位置
- 利用深度优先搜索实现迷宫寻宝,并且在寻找的过程中避开障碍物。
- 搜索算法在线程中进行
定义方格的属性
enum SignalGridType {
SGT_UNLOCK = 0,//通路
SGT_LOCK = -1,//未通路 - 障碍
SGT_TARGET = 100,//目标
SGT_FIND = 200//当前在路径中
};
定义单个方格,并且单个方格具有绘制功能
#pragma once
#include <QColor>
#include <QRect>
#include "MazeDef.h"
class QPainter;
class QImage;
//单个格子
class SignalGrid {
public:
SignalGrid();
~SignalGrid();
void setRow(int r) {
_posRow = r;
}
int getRow() {
return _posRow;
}
void setCol(int c) {
_posCol = c;
}
int getCol() {
return _posCol;
}
void setPosX(int x) {
_rect.setLeft(x);
}
int getPosX() {
return _rect.left();
}
void setPosY(int y) {
_rect.setTop(y);
}
int getPosY() {
return _rect.top();
}
void setSideLength(int len) {
_rect.setWidth(len);
_rect.setHeight(len);
}
int getSideLength() {
return _rect.width();
}
void setGridType(SignalGridType gridType) {
_gridType = gridType;
}
SignalGridType&getGridType() {
return _gridType;
}
bool containtsPt(QPoint pt);
void setSelect(bool b) {
_isSelect = b;
}
bool getSelect() {
return _isSelect;
}
//绘制表格
void drawGrid(QPainter* painter);
void setLockImage(QImage* image) {
_lockImage = image;
}
void setTrgetImage(QImage* image) {
_targetImage = image;
}
private:
bool _isSelect = false;//是否被鼠标选中
int _posRow = -1, _posCol = -1;//行列
QRect _rect;//所在的位置
//当前路径类型
SignalGridType _gridType = SGT_UNLOCK;
QImage* _targetImage = nullptr;
QImage* _lockImage = nullptr;
};
#include "SignalGrid.h"
#include <QPainter>
#include <QImage>
SignalGrid::SignalGrid() {
}
SignalGrid::~SignalGrid() {
}
bool SignalGrid::containtsPt(QPoint pt) {
return _rect.contains(pt);
}
void SignalGrid::drawGrid(QPainter* painter) {
if (_isSelect){
QBrush brush(QColor(255, 255, 0));
painter->setBrush(brush);
painter->setPen(Qt::NoPen);
painter->drawRect(_rect);
}
if (_gridType == SGT_FIND){
QBrush brush(QColor(255, 0, 0));
painter->setBrush(brush);
painter->setPen(Qt::NoPen);
painter->drawRect(_rect);
}
if (_gridType == SGT_TARGET) {
painter->drawImage(_rect, *_targetImage);
} else if (_gridType == SGT_LOCK) {
painter->drawImage(_rect, *_lockImage);
}
}
定义迷宫:
#pragma once
#include "SignalGrid.h"
#include "IFindTarget.h"
class QMouseEvent;
class QPainter;
class QImage;
class IUpdate;
class QtCalThread;
//用户迷宫
#define MAX_ROW 50
#define MAX_COL 50
//迷宫
class UserMaze :public IFindTarget {
public:
UserMaze();
~UserMaze();
virtual void findTarget()override;
void setUpdate(IUpdate* update) {
_update = update;
}
void setMaze(int rowCount, int colCount,int sedeLen);
void setMouseType(SignalGridType type);
virtual void mousePress(QMouseEvent *event);
void mouseMove(QMouseEvent *event);
void mouseRelease(QMouseEvent *event);
void paintEvent(QPainter* painter);
void findByDFS(int x, int y, int step);
void startFind();
protected:
int _rowCount = 0, _colCount = 0;
int _sideLength = 0;
//开始查找的位置
int _startX = 0;
int _startY = 0;
//目标所在的位置
int _targetX = -1;
int _targetY = -1;
SignalGrid _maze[MAX_ROW][MAX_COL];
int _book[MAX_ROW][MAX_COL];
SignalGridType _type = SGT_UNLOCK;
QImage* _targetImage = nullptr;
QImage* _lockImage = nullptr;
IUpdate* _update = nullptr;
QtCalThread* _thread = nullptr;
};
#include "UserMaze.h"
#include <QMouseEvent>
#include <QPainter>
#include <QPoint>
#include <QDebug>
#include <QThread>
#include "IUpdate.h"
#include "QtCalThread.h"
UserMaze::UserMaze() {
_targetImage = new QImage(":/QtGuiMaze/Resources/timg.png");
_lockImage = new QImage(":/QtGuiMaze/Resources/stone.png");
_thread = new QtCalThread(this);
for (int i = 0; i < MAX_ROW; i++) {
for (int j = 0; j < MAX_COL; j++) {
_book[i][j] = 0;
}
}
}
UserMaze::~UserMaze() {
}
void UserMaze::findTarget() {
_book[0][0] = 1;
findByDFS(_startX, _startY, 0);
}
void UserMaze::mousePress(QMouseEvent *event) {
for (int i = 0; i < _rowCount; i++) {
for (int j = 0; j < _colCount; j++) {
if (_maze[i][j].containtsPt(event->pos())) {
if (_maze[i][j].getGridType() == SGT_UNLOCK){
_maze[i][j].setGridType(_type);
if (_type == SGT_TARGET){//保存目标所在的位置
_targetX = i;
_targetY = j;
}
} else {
_maze[i][j].setGridType(SGT_UNLOCK);
}
}
}
}
}
void UserMaze::mouseMove(QMouseEvent *event) {
for (int i = 0; i < _rowCount; i++) {
for (int j = 0; j < _colCount; j++) {
if (_maze[i][j].containtsPt(event->pos())){
_maze[i][j].setSelect(true);
} else {
_maze[i][j].setSelect(false);
}
}
}
}
void UserMaze::mouseRelease(QMouseEvent *event) {
}
void UserMaze::paintEvent(QPainter* painter) {
for (int i = 0; i < _rowCount; i++) {
for (int j = 0; j < _colCount; j++) {
_maze[i][j].drawGrid(painter);
}
}
}
//利用深度优先搜索查找宝物
void UserMaze::findByDFS(int x, int y, int step) {
int next[4][2] = {
{0,1},//向右
{1,0},//向下
{0,-1},//向左
{-1,0}//向上
};
int tx = -1;
int ty = -1;
if (x == _targetX&& y == _targetY) {
_maze[x][y].setGridType(SGT_TARGET);
qDebug() << QStringLiteral("已经找到了!");
return;
}
//分别从四个方向判断
for (int n = 0; n < 4; n++) {
tx = x + next[n][0];
ty = y + next[n][1];
//是否越界
if (tx < 0 || tx >= _rowCount || ty < 0 || ty >= _colCount ) {
continue;
}
//判断改点是否为障碍物或者已经在路径中
if (_maze[tx][ty].getGridType() != SGT_LOCK&& _book[tx][ty] == 0){
_book[tx][ty] = 1;
_maze[tx][ty].setGridType(SGT_FIND);
_update->updateMaze();
QThread::msleep(200);
_maze[tx][ty].setGridType(SGT_UNLOCK);
findByDFS(tx, ty, step + 1);
_book[tx][ty] = 0;
}
}
return;
}
void UserMaze::startFind() {
_thread->start();
}
void UserMaze::setMaze(int rowCount, int colCount, int sideLen) {
_rowCount = rowCount;
_colCount = colCount;
_sideLength = sideLen;
for (int i = 0; i < MAX_ROW; i++) {
for (int j = 0; j < MAX_COL; j++) {
_maze[i][j].setRow(i);
_maze[i][j].setCol(j);
_maze[i][j].setSideLength(_sideLength);
_maze[i][j].setPosX(_sideLength*j);
_maze[i][j].setPosY(_sideLength*i);
_maze[i][j].setLockImage(_lockImage);
_maze[i][j].setTrgetImage(_targetImage);
}
}
}
void UserMaze::setMouseType(SignalGridType type) {
_type = type;
}
构建搜索线程:
#pragma once
#include <QThread>
class IFindTarget;
class QtCalThread : public QThread {
Q_OBJECT
public:
QtCalThread(IFindTarget *target, QObject *parent =nullptr);
~QtCalThread();
virtual void run()override;
private:
IFindTarget* _findTarget = nullptr;
};
#include "QtCalThread.h"
#include "IFindTarget.h"
QtCalThread::QtCalThread(IFindTarget *target, QObject *parent)
: QThread(parent) {
_findTarget = target;
}
QtCalThread::~QtCalThread() {
}
void QtCalThread::run() {
_findTarget->findTarget();
}
定义线程接口:
#pragma once
class IFindTarget {
public:
IFindTarget();
~IFindTarget();
virtual void findTarget() = 0;
};
构建迷宫:
#pragma once
#include <QWidget>
#include "ui_QtGuiGrid.h"
#include "MazeDef.h"
#include "IUpdate.h"
class UserMaze;
class QtGuiGrid : public QWidget,public IUpdate {
Q_OBJECT
public:
QtGuiGrid(QWidget *parent = Q_NULLPTR);
~QtGuiGrid();
virtual void updateMaze()override;
void setGrid(int row,int col);
void setGridRow(int row);
void setGridCol(int col);
void setMouseType(SignalGridType type);
void startFind();
private:
void init();
virtual void paintEvent(QPaintEvent *event)override;
virtual void mousePressEvent(QMouseEvent *event)override;
virtual void mouseMoveEvent(QMouseEvent *event)override;
virtual void mouseReleaseEvent(QMouseEvent *event)override;
private:
Ui::QtGuiGrid ui;
int _row = 0;
int _col = 0;
UserMaze* _userMaze = nullptr;
};
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>
#include "QtGuiGrid.h"
#include "SingleTargetMaze.h"
#define GRID_WIDTH 40
QtGuiGrid::QtGuiGrid(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this);
setMouseTracking(true);
init();
}
QtGuiGrid::~QtGuiGrid() {
}
void QtGuiGrid::updateMaze() {
update();
}
void QtGuiGrid::setGrid(int row, int col) {
_row = row;
_col = col;
update();
}
void QtGuiGrid::setGridRow(int row) {
_row = row;
_userMaze->setMaze(_row, _col, GRID_WIDTH);
update();
}
void QtGuiGrid::setGridCol(int col) {
_col = col;
_userMaze->setMaze(_row, _col, GRID_WIDTH);
update();
}
void QtGuiGrid::setMouseType(SignalGridType type) {
_userMaze->setMouseType(type);
}
void QtGuiGrid::startFind() {
_userMaze->startFind();
}
void QtGuiGrid::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setPen(QPen(Qt::red, 2, Qt::SolidLine));
for (int i = 0; i < _row + 1; i++) {
painter.drawLine(1, i*GRID_WIDTH, _col*GRID_WIDTH, i*GRID_WIDTH);
}
for (int j = 0; j < _col + 1; j++) {
painter.drawLine(j*GRID_WIDTH, 1, j*GRID_WIDTH, _row*GRID_WIDTH);
}
//绘制单个表格
_userMaze->paintEvent(&painter);
}
void QtGuiGrid::mousePressEvent(QMouseEvent *event) {
_userMaze->mousePress(event);
update();
}
void QtGuiGrid::mouseMoveEvent(QMouseEvent *event) {
//qDebug() << QString("X:%1 - Y:%2").arg(event->pos().x()).arg(event->pos().y());
_userMaze->mouseMove(event);
update();
}
void QtGuiGrid::mouseReleaseEvent(QMouseEvent *event) {
_userMaze->mouseRelease(event);
update();
}
void QtGuiGrid::init() {
_userMaze = new SingleTargetMaze;
_userMaze->setUpdate(this);
_col = 12;
_row = 12;
_userMaze->setMaze(_row, _col, GRID_WIDTH);
}
构造框架:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtGuiMaze.h"
class QtGuiGrid;
class QtGuiMaze : public QMainWindow {
Q_OBJECT
public:
QtGuiMaze(QWidget *parent = Q_NULLPTR);
private:
void init();
private slots:
void slotRowChange(const QString &row);
void slotColChange(const QString &col);
void slotBtnObj(int);
void slotBtnStart();
private:
Ui::QtGuiMazeClass ui;
QtGuiGrid* _guiGrid = nullptr;
};
#include "QtGuiMaze.h"
#include "QtGuiGrid.h"
QtGuiMaze::QtGuiMaze(QWidget *parent)
: QMainWindow(parent) {
ui.setupUi(this);
init();
}
void QtGuiMaze::init() {
_guiGrid = new QtGuiGrid(nullptr);
ui.verticalLayout->addWidget(_guiGrid);
connect(ui.lineEditRow, SIGNAL(textChanged(const QString &)), this, SLOT(slotRowChange(const QString &)));
connect(ui.lineEditCol, SIGNAL(textChanged(const QString &)), this, SLOT(slotColChange(const QString &)));
ui.buttonGroup->addButton(ui.radioButtonTarget, 100);
ui.buttonGroup->addButton(ui.radioButtonHinder, 101);
connect(ui.buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotBtnObj(int)));//连接信号和槽
connect(ui.pushButtonStart, SIGNAL(clicked()), this, SLOT(slotBtnStart()));//连接信号和槽
int row = 10, col = 10;
ui.lineEditRow->setText(QString::number(row));
ui.lineEditCol->setText(QString::number(col));
_guiGrid->setGridRow(row);
_guiGrid->setGridCol(col);
}
void QtGuiMaze::slotRowChange(const QString &row) {
_guiGrid->setGridRow(row.toInt());
}
void QtGuiMaze::slotColChange(const QString &col) {
_guiGrid->setGridCol(col.toInt());
}
void QtGuiMaze::slotBtnObj(int buttonID) {
switch (buttonID) {
case 100:
_guiGrid->setMouseType(SGT_TARGET);
break;
case 101:
_guiGrid->setMouseType(SGT_LOCK);
break;
}
}
void QtGuiMaze::slotBtnStart() {
_guiGrid->startFind();
}
源码下载
aaa