From 9c47a6818ffe5a12483c718165a3b959ca75eabe Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 <0xFEEDC0DE64@gmail.com> Date: Sat, 15 Sep 2018 20:53:01 +0200 Subject: [PATCH] Imported existing sources --- DbPathFinder.pro | 24 ++++++ main.cpp | 17 ++++ mainwindow.cpp | 114 +++++++++++++++++++++++++++ mainwindow.h | 35 +++++++++ mainwindow.ui | 116 ++++++++++++++++++++++++++++ mywidget.cpp | 197 +++++++++++++++++++++++++++++++++++++++++++++++ mywidget.h | 51 ++++++++++++ 7 files changed, 554 insertions(+) create mode 100644 DbPathFinder.pro create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 mywidget.cpp create mode 100644 mywidget.h diff --git a/DbPathFinder.pro b/DbPathFinder.pro new file mode 100644 index 0000000..a32d2de --- /dev/null +++ b/DbPathFinder.pro @@ -0,0 +1,24 @@ +QT += core gui widgets + +DBLIBS += + +TARGET = pathfinder + +PROJECT_ROOT = .. + +SOURCES += main.cpp \ + mywidget.cpp \ + mainwindow.cpp + +HEADERS += \ + mywidget.h \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +RESOURCES += + +TRANSLATIONS += + +include($${PROJECT_ROOT}/app.pri) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..3df1ab1 --- /dev/null +++ b/main.cpp @@ -0,0 +1,17 @@ +#include +#include +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + qsrand(QDateTime::currentMSecsSinceEpoch()); + + MainWindow mainWindow; + mainWindow.show(); + + return app.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..4136991 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,114 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + ui->widget->reset(ui->spinBoxColumns->value(), ui->spinBoxRows->value()); + + m_timer = new QTimer(this); + m_timer->setInterval(1000/30); + + connect(ui->pushButtonReset, &QAbstractButton::pressed, this, &MainWindow::reset); + connect(ui->pushButtonStep, &QAbstractButton::pressed, this, &MainWindow::step); + connect(ui->pushButtonAnimate, &QAbstractButton::pressed, this, &MainWindow::animate); + connect(ui->pushButtonSolve, &QAbstractButton::pressed, this, &MainWindow::solve); + connect(m_timer, &QTimer::timeout, this, &MainWindow::timeout); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::reset() +{ + ui->widget->reset(ui->spinBoxColumns->value(), ui->spinBoxRows->value()); + ui->widget->repaint(); + + ui->pushButtonStep->setEnabled(true); + ui->pushButtonAnimate->setEnabled(true); + ui->pushButtonSolve->setEnabled(true); +} + +MyWidget::Result MainWindow::step() +{ + auto result = ui->widget->compute(); + ui->widget->repaint(); + switch(result) + { + case MyWidget::Result::Solved: + solved(); + break; + case MyWidget::Result::NotSolvable: + notSolvable(); + break; + } + return result; +} + +void MainWindow::animate() +{ + ui->spinBoxColumns->setEnabled(false); + ui->spinBoxRows->setEnabled(false); + ui->pushButtonReset->setEnabled(false); + ui->pushButtonStep->setEnabled(false); + ui->pushButtonAnimate->setEnabled(false); + ui->pushButtonSolve->setEnabled(false); + + m_timer->start(); +} + +void MainWindow::solve() +{ + MyWidget::Result result; + while((result = ui->widget->compute()) == MyWidget::Result::NotFinished); + ui->widget->repaint(); + switch (result) { + case MyWidget::Result::Solved: + solved(); + break; + case MyWidget::Result::NotSolvable: + notSolvable(); + break; + default: + Q_UNREACHABLE(); + } +} + +void MainWindow::timeout() +{ + auto result = step(); + switch(result) + { + case MyWidget::Result::Solved: + case MyWidget::Result::NotSolvable: + m_timer->stop(); + ui->spinBoxColumns->setEnabled(true); + ui->spinBoxRows->setEnabled(true); + ui->pushButtonReset->setEnabled(true); + break; + } +} + +void MainWindow::solved() +{ + QMessageBox::information(this, tr("Found the optimal solution"), tr("The optimal solution was found and will be drawn in darker green.")); + ui->pushButtonStep->setEnabled(false); + ui->pushButtonAnimate->setEnabled(false); + ui->pushButtonSolve->setEnabled(false); +} + +void MainWindow::notSolvable() +{ + QMessageBox::warning(this, tr("No solution found"), tr("There is no solution!")); + ui->pushButtonStep->setEnabled(false); + ui->pushButtonAnimate->setEnabled(false); + ui->pushButtonSolve->setEnabled(false); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..81d0e7f --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,35 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +#include "mywidget.h" + +class QTimer; + +namespace Ui { class MainWindow; } + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private Q_SLOTS: + void reset(); + MyWidget::Result step(); + void animate(); + void solve(); + void timeout(); + +private: + void solved(); + void notSolvable(); + + Ui::MainWindow *ui; + QTimer *m_timer; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..19be35a --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,116 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + + + 5 + + + 500 + + + 50 + + + + + + + 5 + + + 500 + + + 50 + + + + + + + Reset + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Step + + + + + + + Animate + + + + + + + Solve + + + + + + + + + + + + + + 0 + 0 + 800 + 22 + + + + + + + + MyWidget + QWidget +
mywidget.h
+ 1 +
+
+ + +
diff --git a/mywidget.cpp b/mywidget.cpp new file mode 100644 index 0000000..17f6339 --- /dev/null +++ b/mywidget.cpp @@ -0,0 +1,197 @@ +#include "mywidget.h" + +//#define ACUTE_ANGLE + +#include +#include +#include +#include +#include +#include + +MyWidget::MyWidget(QWidget *parent) : + QWidget(parent), + m_start(Q_NULLPTR), + m_end(Q_NULLPTR) +{ +} + +void MyWidget::reset(int columns, int rows) +{ + m_nodes.resize(rows); + for(int y = 0; y < rows; y++) + m_nodes[y].resize(columns); + + for(int y = 0; y < m_nodes.count(); y++) + for(int x = 0; x < m_nodes.at(y).count(); x++) + { + Node &node = m_nodes[y][x]; + node.wall = !(x == 0 && y == 0) && + !(x == m_nodes.at(y).count() -1 && y == m_nodes.count() - 1) && + qrand() < RAND_MAX / 3; + node.x = x; + node.y = y; + node.connections.clear(); + node.f = 0; + node.g = 0; + node.h = 0; + node.previous = 0; + } + + for(const auto &vector : m_nodes) + for(const auto &node : vector) + { + if(node.wall) + continue; + + auto x = node.x; + auto y = node.y; + + if(x > 0 && !m_nodes.at(y).at(x - 1).wall) + m_nodes[y][x].connections.append(&m_nodes[y][x - 1]); + if(x < m_nodes.at(y).count() - 1 && !m_nodes.at(y).at(x + 1).wall) + m_nodes[y][x].connections.append(&m_nodes[y][x + 1]); + if(y > 0 && !m_nodes.at(y - 1).at(x).wall) + m_nodes[y][x].connections.append(&m_nodes[y - 1][x]); + if(y < m_nodes.count() - 1 && !m_nodes.at(y + 1).at(x).wall) + m_nodes[y][x].connections.append(&m_nodes[y + 1][x]); + +#ifdef ACUTE_ANGLE + if(x > 0 && y > 0 && !m_nodes.at(y - 1).at(x - 1).wall && !m_nodes.at(y).at(x - 1).wall && !m_nodes.at(y - 1).at(x).wall) + m_nodes[y][x].connections.append(&m_nodes[y - 1][x - 1]); + if(x < m_nodes.at(y).count() - 1 && y > 0 && !m_nodes.at(y - 1).at(x + 1).wall && !m_nodes.at(y).at(x + 1).wall && !m_nodes.at(y - 1).at(x).wall) + m_nodes[y][x].connections.append(&m_nodes[y - 1][x + 1]); + if(x > 0 && y < m_nodes.count() - 1 && !m_nodes.at(y + 1).at(x - 1).wall && !m_nodes.at(y).at(x - 1).wall && !m_nodes.at(y + 1).at(x).wall) + m_nodes[y][x].connections.append(&m_nodes[y + 1][x - 1]); + if(x < m_nodes.at(y).count() - 1 && y < m_nodes.count() - 1 && !m_nodes.at(y + 1).at(x + 1).wall && !m_nodes.at(y).at(x + 1).wall && !m_nodes.at(y + 1).at(x).wall) + m_nodes[y][x].connections.append(&m_nodes[y + 1][x + 1]); +#endif + } + + m_start = &m_nodes.constFirst().constFirst(); + m_end = &m_nodes.constLast().constLast(); + + m_openSet = { m_start }; + m_closedSet.clear(); + m_result.clear(); +} + +MyWidget::Result MyWidget::compute() +{ + if(m_openSet.count()) + { + int lowestFIndex = 0; + for(int i = 1; i < m_openSet.count(); i++) + if(m_openSet.at(i)->f < m_openSet.at(lowestFIndex)->f) + lowestFIndex = i; + + auto current = m_openSet.at(lowestFIndex); + + { + auto test = current; + m_result.clear(); + do + { + m_result.append(test); + test = test->previous; + } + while(test); + } + + if(current != m_end) + { + m_openSet.removeAll(current); + m_closedSet.append(current); + + for(const auto &neighbour : current->connections) + { + if(!m_closedSet.contains(neighbour)) + { + auto increasedG = current->g + +#ifdef ACUTE_ANGLE + QLineF(current->x, current->y, neighbour->x, neighbour->y).length(); +#else + qAbs(current->x - neighbour->x) + qAbs(current->y - neighbour->y); +#endif + bool newPath = false; + + if(m_openSet.contains(neighbour)) + { + if(increasedG < neighbour->g) + newPath = true; + } + else + { + newPath = true; + m_openSet.append(neighbour); + } + + if(newPath) + { + m_nodes[neighbour->y][neighbour->x].g = increasedG; + m_nodes[neighbour->y][neighbour->x].h = +#ifdef ACUTE_ANGLE + QLineF(neighbour->x, neighbour->y, m_end->x, m_end->y).length(); +#else + qAbs(neighbour->x - m_end->x) + qAbs(neighbour->y - m_end->y); +#endif + m_nodes[neighbour->y][neighbour->x].f = neighbour->g + neighbour->h; + m_nodes[neighbour->y][neighbour->x].previous = current; + } + } + } + } + else + return Result::Solved; + } + else + return Result::NotSolvable; + + return Result::NotFinished; +} + +void MyWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + + if(!m_nodes.count()) + return; + + QPainter painter(this); + + painter.setPen(Qt::NoPen); + + auto boxHeight = height() / m_nodes.count(); + + for(const auto &vector : m_nodes) + { + auto boxWidth = width() / vector.count(); + + for(const auto &node : vector) + { + if(m_result.contains(&node)) + painter.setBrush(Qt::darkGreen); + else if(m_closedSet.contains(&node)) + painter.setBrush(Qt::red); + else if(m_openSet.contains(&node)) + painter.setBrush(Qt::green); + else if(node.wall) + painter.setBrush(Qt::black); + else + continue; + + painter.drawRect(node.x * boxWidth, node.y * boxHeight, boxWidth, boxHeight); + } + } + + painter.setPen(Qt::blue); + + for(const auto &vector : m_nodes) + { + auto boxWidth = width() / vector.count(); + + for(const auto &node : vector) + for(const auto &otherNode : node.connections) + painter.drawLine((node.x * boxWidth) + (boxWidth / 2), (node.y * boxHeight) + (boxHeight / 2), (otherNode->x * boxWidth) + (boxWidth / 2), (otherNode->y * boxHeight) + (boxHeight / 2)); + } +} diff --git a/mywidget.h b/mywidget.h new file mode 100644 index 0000000..0203fb0 --- /dev/null +++ b/mywidget.h @@ -0,0 +1,51 @@ +#ifndef MYWIDGET_H +#define MYWIDGET_H + +#include +#include + +class QTimer; + +class MyWidget : public QWidget +{ + Q_OBJECT + +public: + enum class Result + { + NotFinished, + Solved, + NotSolvable + }; + + explicit MyWidget(QWidget *parent = Q_NULLPTR); + void reset(int columns, int rows); + Result compute(); + +protected: + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; + +private: + struct Node { + bool wall; + int x; + int y; + QVector connections; + + //algorithm specific + qreal f; + qreal g; + qreal h; + const Node *previous; + }; + + QVector > m_nodes; + + QVector m_openSet; + QVector m_closedSet; + const Node *m_start; + const Node *m_end; + QVector m_result; +}; + +#endif // MYWIDGET_H