#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)); } }