Qt利用深度优先搜索实现迷宫寻宝

先看效果:
在这里插入图片描述

  1. 利用QT搭建迷宫界面
  2. 利用单选框来构造迷宫,设置障碍物和宝藏的位置
  3. 利用深度优先搜索实现迷宫寻宝,并且在寻找的过程中避开障碍物。
  4. 搜索算法在线程中进行

定义方格的属性

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wb175208

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值