Imported existing sources

This commit is contained in:
0xFEEDC0DE64
2018-09-15 20:53:01 +02:00
parent 2e7c101d29
commit 9c47a6818f
7 changed files with 554 additions and 0 deletions

24
DbPathFinder.pro Normal file
View File

@ -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)

17
main.cpp Normal file
View File

@ -0,0 +1,17 @@
#include <QApplication>
#include <qglobal.h>
#include <QDateTime>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qsrand(QDateTime::currentMSecsSinceEpoch());
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}

114
mainwindow.cpp Normal file
View File

@ -0,0 +1,114 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTimer>
#include <QMessageBox>
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);
}

35
mainwindow.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#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

116
mainwindow.ui Normal file
View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="spinBoxColumns">
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>500</number>
</property>
<property name="value">
<number>50</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxRows">
<property name="minimum">
<number>5</number>
</property>
<property name="maximum">
<number>500</number>
</property>
<property name="value">
<number>50</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonReset">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButtonStep">
<property name="text">
<string>Step</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonAnimate">
<property name="text">
<string>Animate</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonSolve">
<property name="text">
<string>Solve</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="MyWidget" name="widget" native="true"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>MyWidget</class>
<extends>QWidget</extends>
<header>mywidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

197
mywidget.cpp Normal file
View File

@ -0,0 +1,197 @@
#include "mywidget.h"
//#define ACUTE_ANGLE
#include <QTimer>
#include <QPainter>
#include <QDebug>
#include <QLine>
#include <QLineF>
#include <QMessageBox>
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));
}
}

51
mywidget.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QVector>
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<const Node *> connections;
//algorithm specific
qreal f;
qreal g;
qreal h;
const Node *previous;
};
QVector<QVector<Node> > m_nodes;
QVector<const Node *> m_openSet;
QVector<const Node *> m_closedSet;
const Node *m_start;
const Node *m_end;
QVector<const Node *> m_result;
};
#endif // MYWIDGET_H