随机生成一张表格图,每个小格子只有两个值0或者1,随机的选中一个格子,然后与其相邻(上下左右)的具有想同值的格子进行着色,查找周围格子的时候使用的两种算法:深度优先搜索和广度优先搜索。
广度优先搜索示例:
深度优先搜索示例:
主界面:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_FloodFill.h"
#include "IUpdateMap.h"
class Islands;
class FloodFill : public QMainWindow,public IUpdateMap {
Q_OBJECT
public:
FloodFill(QWidget *parent = Q_NULLPTR);
virtual void updateMap()override;
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::FloodFillClass ui;
Islands* _isLand = nullptr;
};
#include "FloodFill.h"
#include <QPainter>
#include <QMouseEvent>
#include "Islands.h"
FloodFill::FloodFill(QWidget *parent)
: QMainWindow(parent) {
ui.setupUi(this);
setMouseTracking(true);
ui.centralWidget->setMouseTracking(true);
init();
}
void FloodFill::updateMap() {
update();
}
void FloodFill::init() {
_isLand = new Islands(20, 20);
_isLand->setUpdateCallback(this);
}
void FloodFill::paintEvent(QPaintEvent *event) {
QPainter painter(this);
_isLand->drawIsLand(&painter);
}
void FloodFill::mousePressEvent(QMouseEvent *event) {
}
void FloodFill::mouseMoveEvent(QMouseEvent *event) {
}
void FloodFill::mouseReleaseEvent(QMouseEvent *event) {
QPoint pt = event->pos();
_isLand->selectGrid(pt);
}
查找接口:
#pragma once
class IFind {
public:
IFind();
~IFind();
virtual void find();
};
#include "IFind.h"
IFind::IFind() {
}
IFind::~IFind() {
}
void IFind::find() {
}
地图岛:
#pragma once
#include <vector>
#include <QPoint>
#include "IFind.h"
//岛屿
class QPainter;
class QtFindThread;
class SignalGridItem;
class IUpdateMap;
class Islands:public IFind {
public:
Islands(int w,int h);
~Islands();
void drawIsLand(QPainter* p);
void selectGrid(QPoint pt);
void setUpdateCallback(IUpdateMap* updateMap);
virtual void find()override;
private:
int getType();
void findBFS();
void findDFS(QPoint pt);
private:
int _width = 0;
int _height = 0;
int _sideLength = 20;//边长
QPoint _selectPos = QPoint(-1, -1);//选中的表格位置
int _selectValue = -1;//选中的格子的值
std::vector<std::vector<SignalGridItem*>> _grid ;
std::vector<std::vector<bool>> _book;
QtFindThread* _findThread = nullptr;
IUpdateMap* _updateMap = nullptr;//地图更新接口
};
#include "Islands.h"
#include "SignalGridItem.h"
#include <QTime>
#include <QPainter>
#include <queue>
#include "LandGridItem.h"
#include "SeaGridItem.h"
#include "QtFindThread.h"
#include "IUpdateMap.h"
#include<QThread>
#include<QRandomGenerator>
Islands::Islands(int w, int h) {
_width = w;
_height = h;
SignalGridItem* temp = nullptr;
for (int i = 0; i < _height; i++) {
std::vector<SignalGridItem*> oneRow;
for (int j = 0; j < _width; j++) {
int type = getType();
if (type == 0){
temp = new SeaGridItem();
} else {
temp = new LandGridItem();
}
temp->setX(i);
temp->setY(j);
QRect rect(_sideLength*j, _sideLength*i, _sideLength, _sideLength);
temp->setRect(rect);
temp->setValue(type);
oneRow.push_back(temp);
}
_grid.push_back(oneRow);
}
_findThread = new QtFindThread(nullptr);
_findThread->setCallback(this);
}
Islands::~Islands() {
}
void Islands::drawIsLand(QPainter* p) {
p->setPen(QPen(Qt::red, 2, Qt::SolidLine));
for (int i = 0; i < _width + 1; i++) {
p->drawLine(1, i*_sideLength, _height*_sideLength, i*_sideLength);
}
for (int j = 0; j < _height + 1; j++) {
p->drawLine(j*_sideLength, 1, j*_sideLength, _width*_sideLength);
}
for (int i = 0; i < _width; i++) {
for (int j = 0; j < _height; j++) {
_grid[i][j]->drawGridItem(p);
}
}
}
void Islands::selectGrid(QPoint pt) {
for (int i = 0; i < _height; i++) {
std::vector<bool> oneLine;
for (int j = 0; j < _width; j++) {
oneLine.push_back(false);
}
_book.push_back(oneLine);
}
bool isSelect = false;
for (int i = 0; i < _height; i++) {
for (int j = 0; j < _width; j++) {
if (_grid[i][j]->containtsPt(pt)){
_grid[i][j]->setGrawBK(true);
_selectPos = QPoint(i, j);
_selectValue = _grid[i][j]->getValue();
isSelect = true;
_book[i][j] = true;
break;
}
}
if (isSelect){
_findThread->start();
break;
}
}
}
void Islands::setUpdateCallback(IUpdateMap* updateMap) {
_updateMap = updateMap;
}
void Islands::find() {
#if 0//广度优先搜索
findBFS();
#else//深度优先搜索
findDFS(_selectPos);
#endif
}
int Islands::getType() {
int randNum = QRandomGenerator::global()->bounded(10);//生成一个0和10之间的整数
int n = randNum % 2; //产生随机数
return n;
}
//广度优先搜索
void Islands::findBFS() {
int next[4][2] = {//按照顺时针方向搜索
{ 0,1 },//向右
{ 1,0 },//向下
{ 0,-1 },//向左
{ -1,0 }//向上
};
std::queue<QPoint> posList;
posList.push(_selectPos);
while (posList.size()>0) {
for (int i =0;i< 4;i++){
QPoint ptNext = posList.front() + QPoint(next[i][0], next[i][1]);
//越界判断
if (ptNext.x() < 0 || ptNext.x() >= _height || ptNext.y() < 0 || ptNext.y() >= _width) {
continue;
}
if (_grid[ptNext.x()][ptNext.y()]->getValue() == _selectValue && !_book[ptNext.x()][ptNext.y()]){
_grid[ptNext.x()][ptNext.y()]->setGrawBK(true);
_book[ptNext.x()][ptNext.y()] = true;
_updateMap->updateMap();
QThread::msleep(50);
posList.push(ptNext);
}
}
posList.pop();
}
}
//深度优先搜索
void Islands::findDFS(QPoint pt) {
int next[4][2] = {//按照顺时针方向搜索
{ 0,1 },//向右
{ 1,0 },//向下
{ 0,-1 },//向左
{ -1,0 }//向上
};
for (int i = 0; i < 4; i++) {
QPoint ptNext = pt + QPoint(next[i][0], next[i][1]);
//越界判断
if (ptNext.x() < 0 || ptNext.x() >= _height || ptNext.y() < 0 || ptNext.y() >= _width) {
continue;
}
//是选中
if (_grid[ptNext.x()][ptNext.y()]->getValue() == _selectValue && !_book[ptNext.x()][ptNext.y()]) {
_grid[ptNext.x()][ptNext.y()]->setGrawBK(true);
_book[ptNext.x()][ptNext.y()] = true;
_updateMap->updateMap();
QThread::msleep(50);
findDFS(ptNext);
}
}
}
地图更新接口:
#pragma once
class IUpdateMap {
public:
IUpdateMap();
~IUpdateMap();
virtual void updateMap() = 0;
};
#include "IUpdateMap.h"
IUpdateMap::IUpdateMap() {
}
IUpdateMap::~IUpdateMap() {
}
单个格子
#pragma once
#include <QRect>
#include <QPoint>
//单个格子
class QPainter;
class SignalGridItem {
public:
SignalGridItem();
SignalGridItem(int x,int y,int v);
~SignalGridItem();
void setX(int x) {
_x = x;
}
int&getX() {
return _x;
}
void setY(int y) {
_y = y;
}
int&getY() {
return _y;
}
void setValue(int v) {
_value = v;
}
int&getValue() {
return _value;
}
void setRect(QRect rect) {
_rect = rect;
}
void setGrawBK(bool b) {
_isDrawBK = b;
}
bool containtsPt(QPoint pt);
virtual void drawGridItem(QPainter* p);
protected:
int _x = -1;
int _y = -1;
int _value = 0;//0-海洋 1-陆地
QRect _rect;
bool _isDrawBK = false;//是否绘制背景
};
#include "SignalGridItem.h"
#include <QPainter>
SignalGridItem::SignalGridItem() {
_isDrawBK = false;
}
SignalGridItem::SignalGridItem(int x, int y, int v) {
_x = x;
_y = y;
_value = v;
}
SignalGridItem::~SignalGridItem() {
}
bool SignalGridItem::containtsPt(QPoint pt) {
return _rect.contains(pt);
}
void SignalGridItem::drawGridItem(QPainter* p) {
p->setPen(QPen(Qt::black));
QString valueStr = QString::number(_value);
p->drawText(_rect, Qt::AlignCenter, valueStr);
}
陆地格子
#pragma once
#include "SignalGridItem.h"
//陆地格子
class LandGridItem :public SignalGridItem {
public:
LandGridItem();
~LandGridItem();
virtual void drawGridItem(QPainter* p)override;
};
#include "LandGridItem.h"
#include <QPainter>
LandGridItem::LandGridItem() {
}
LandGridItem::~LandGridItem() {
}
void LandGridItem::drawGridItem(QPainter* p) {
if (_isDrawBK) {
p->setBrush(QBrush(Qt::green));
p->drawRect(_rect);
}
SignalGridItem::drawGridItem(p);
}
海洋格子
#pragma once
#include "SignalGridItem.h"
//海洋格子
class QPainter;
class SeaGridItem :public SignalGridItem {
public:
SeaGridItem();
~SeaGridItem();
virtual void drawGridItem(QPainter* p)override;
};
#include "SeaGridItem.h"
#include <QPainter>
SeaGridItem::SeaGridItem() {
}
SeaGridItem::~SeaGridItem() {
}
void SeaGridItem::drawGridItem(QPainter* p) {
if (_isDrawBK){
p->setBrush(QBrush(Qt::blue));
p->drawRect(_rect);
}
SignalGridItem::drawGridItem(p);
}
查找线程
#pragma once
#include <QThread>
class IFind;
class QtFindThread : public QThread {
Q_OBJECT
public:
QtFindThread(QObject *parent);
~QtFindThread();
virtual void run()override;
void setCallback(IFind* find);
private:
IFind* _find = nullptr;
};
#include "QtFindThread.h"
#include "IFind.h"
QtFindThread::QtFindThread(QObject *parent)
: QThread(parent) {
}
QtFindThread::~QtFindThread() {
}
void QtFindThread::run() {
_find->find();
}
void QtFindThread::setCallback(IFind* find) {
_find = find;
}
aaa