File indexing completed on 2023-10-01 08:02:06
0001 /* 0002 SPDX-FileCopyrightText: 2007-2008 Thomas Gallinari <tg8187@yahoo.fr> 0003 SPDX-FileCopyrightText: 2007-2008 Pierre-BenoƮt Besse <besse.pb@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "maze.h" 0009 0010 #include <QDebug> 0011 #include <cmath> 0012 0013 Maze::Maze() 0014 : m_totalNbElem(0) 0015 , m_nbElem(0) 0016 { 0017 } 0018 0019 Maze::~Maze() 0020 { 0021 for (int i = 0; i < m_nbRows; ++i) { 0022 delete[] m_cells[i]; 0023 } 0024 delete[] m_cells; 0025 } 0026 0027 void Maze::init(const int p_nbRows, const int p_nbColumns) 0028 { 0029 m_nbRows = p_nbRows; 0030 m_nbColumns = p_nbColumns; 0031 m_cells = new Cell *[m_nbRows]; 0032 for (int i = 0; i < m_nbRows; ++i) { 0033 m_cells[i] = new Cell[m_nbColumns]; 0034 } 0035 } 0036 0037 void Maze::setCellType(const int p_row, const int p_column, const Cell::Type p_type) 0038 { 0039 if (p_row < 0 || p_row >= m_nbRows || p_column < 0 || p_column >= m_nbColumns) { 0040 qCritical() << "Bad maze coordinates"; 0041 } 0042 m_cells[p_row][p_column].setType(p_type); 0043 } 0044 0045 void Maze::setCellElement(const int p_row, const int p_column, Element *p_element) 0046 { 0047 if (p_row < 0 || p_row >= m_nbRows || p_column < 0 || p_column >= m_nbColumns) { 0048 qCritical() << "Bad maze coordinates"; 0049 } 0050 m_cells[p_row][p_column].setElement(p_element); 0051 if (p_element != nullptr) { 0052 m_totalNbElem++; 0053 m_nbElem++; 0054 } 0055 } 0056 0057 void Maze::setResurrectionCell(QPoint p_resurrectionCell) 0058 { 0059 // TODO : COORDINATES INVERTED, NEED TO CORRECT IT in the findPAth algorithm 0060 m_resurrectionCell.setX(p_resurrectionCell.y()); 0061 m_resurrectionCell.setY(p_resurrectionCell.x()); 0062 } 0063 0064 void Maze::decrementNbElem() 0065 { 0066 m_nbElem--; 0067 if (m_nbElem == 0) { 0068 Q_EMIT allElementsEaten(); 0069 } 0070 } 0071 0072 void Maze::resetNbElem() 0073 { 0074 m_nbElem = m_totalNbElem; 0075 } 0076 0077 QList<QPoint> Maze::getPathToGhostCamp(const int p_row, const int p_column) const 0078 { 0079 QList<QPoint> path; 0080 QList<QPoint> openList; 0081 QList<QPoint> closedList; 0082 QPoint currentCell; 0083 QPoint tmpCell; 0084 int lowestCost; 0085 int icurrent = 0; 0086 int oldSize = 0; 0087 0088 // Initialize the starting cell 0089 m_cells[p_row][p_column].setCost(abs(m_resurrectionCell.y() - p_row) + abs(m_resurrectionCell.x() - p_column)); 0090 // Add the starting cell to the openList 0091 openList.append(QPoint(p_column, p_row)); 0092 // While the closed list does not contain the target cell 0093 while (!closedList.contains(QPoint(m_resurrectionCell.x(), m_resurrectionCell.y())) && openList.size() != oldSize) { 0094 // Look for the lowest cost cell on the open list 0095 lowestCost = 1000; 0096 for (int i = 0; i < openList.size(); ++i) { 0097 if (m_cells[openList[i].y()][openList[i].x()].getCost() < lowestCost) { 0098 lowestCost = m_cells[openList[i].y()][openList[i].x()].getCost(); 0099 currentCell = openList[i]; 0100 icurrent = i; 0101 } 0102 } 0103 // Switch this cell to the closed list 0104 closedList.append(currentCell); 0105 openList.removeAt(icurrent); 0106 oldSize = openList.size(); 0107 // For each of the 4 cells adjacent to the current node 0108 // Left 0109 tmpCell.setX(currentCell.x() - 1); 0110 tmpCell.setY(currentCell.y()); 0111 if (m_cells[tmpCell.y()][tmpCell.x()].getType() != Cell::WALL) { 0112 // If the cell is not in the closed list or the open list 0113 if (!closedList.contains(tmpCell) && !openList.contains(tmpCell)) { 0114 // Initialize the cell 0115 m_cells[tmpCell.y()][tmpCell.x()].setCost(abs(m_resurrectionCell.y() - tmpCell.y()) + abs(m_resurrectionCell.x() - (tmpCell.x()))); 0116 m_cells[tmpCell.y()][tmpCell.x()].setParent(&m_cells[currentCell.y()][currentCell.x()]); 0117 // Add it to the open list 0118 openList.append(tmpCell); 0119 } 0120 } 0121 // Right 0122 tmpCell.setX(currentCell.x() + 1); 0123 tmpCell.setY(currentCell.y()); 0124 if (m_cells[tmpCell.y()][tmpCell.x()].getType() != Cell::WALL) { 0125 // If the cell is not in the closed list or the open list 0126 if (!closedList.contains(tmpCell) && !openList.contains(tmpCell)) { 0127 // Initialize the cell 0128 m_cells[tmpCell.y()][tmpCell.x()].setCost(abs(m_resurrectionCell.y() - tmpCell.y()) + abs(m_resurrectionCell.x() - (tmpCell.x()))); 0129 m_cells[tmpCell.y()][tmpCell.x()].setParent(&m_cells[currentCell.y()][currentCell.x()]); 0130 // Add it to the open list 0131 openList.append(tmpCell); 0132 } 0133 } 0134 // Top 0135 tmpCell.setX(currentCell.x()); 0136 tmpCell.setY(currentCell.y() - 1); 0137 if (m_cells[tmpCell.y()][tmpCell.x()].getType() != Cell::WALL) { 0138 // If the cell is not in the closed list or the open list 0139 if (!closedList.contains(tmpCell) && !openList.contains(tmpCell)) { 0140 // Initialize the cell 0141 m_cells[tmpCell.y()][tmpCell.x()].setCost(abs(m_resurrectionCell.y() - tmpCell.y()) + abs(m_resurrectionCell.x() - (tmpCell.x()))); 0142 m_cells[tmpCell.y()][tmpCell.x()].setParent(&m_cells[currentCell.y()][currentCell.x()]); 0143 // Add it to the open list 0144 openList.append(tmpCell); 0145 } 0146 } 0147 // Bottom 0148 tmpCell.setX(currentCell.x()); 0149 tmpCell.setY(currentCell.y() + 1); 0150 if (m_cells[tmpCell.y()][tmpCell.x()].getType() != Cell::WALL) { 0151 // If the cell is not in the closed list or the open list 0152 if (!closedList.contains(tmpCell) && !openList.contains(tmpCell)) { 0153 // Initialize the cell 0154 m_cells[tmpCell.y()][tmpCell.x()].setCost(abs(m_resurrectionCell.y() - tmpCell.y()) + abs(m_resurrectionCell.x() - (tmpCell.x()))); 0155 m_cells[tmpCell.y()][tmpCell.x()].setParent(&m_cells[currentCell.y()][currentCell.x()]); 0156 // Add it to the open list 0157 openList.append(tmpCell); 0158 } 0159 } 0160 } 0161 if (oldSize == openList.size()) { 0162 qCritical() << "Path to ghost home not found"; 0163 return {}; 0164 } 0165 // Save the path : from the target cell, go from each cell to its parent cell until reaching the starting cell 0166 for (Cell *cell = &m_cells[m_resurrectionCell.y()][m_resurrectionCell.x()]; cell->getParent() != &m_cells[p_row][p_column]; cell = cell->getParent()) { 0167 path.prepend(getCoords(cell)); 0168 } 0169 0170 return path; 0171 } 0172 0173 Cell Maze::getCell(const int p_row, const int p_column) const 0174 { 0175 if (p_row < 0 || p_row >= m_nbRows || p_column < 0 || p_column >= m_nbColumns) { 0176 qCritical() << "Bad maze coordinates"; 0177 } 0178 return m_cells[p_row][p_column]; 0179 } 0180 0181 QPoint Maze::getCoords(Cell *p_cell) const 0182 { 0183 for (int i = 0; i < m_nbRows; ++i) { 0184 for (int j = 0; j < m_nbColumns; ++j) { 0185 if (&m_cells[i][j] == p_cell) { 0186 return {j, i}; 0187 } 0188 } 0189 } 0190 return {}; 0191 } 0192 0193 int Maze::getRowFromY(const qreal p_y) const 0194 { 0195 return (int)(p_y / Cell::SIZE); 0196 } 0197 0198 int Maze::getColFromX(const qreal p_x) const 0199 { 0200 return (int)(p_x / Cell::SIZE); 0201 } 0202 0203 int Maze::getNbColumns() const 0204 { 0205 return m_nbColumns; 0206 } 0207 0208 int Maze::getNbRows() const 0209 { 0210 return m_nbRows; 0211 } 0212 0213 int Maze::getNbElem() const 0214 { 0215 return m_nbElem; 0216 } 0217 0218 int Maze::getTotalNbElem() const 0219 { 0220 return m_totalNbElem; 0221 } 0222 0223 QPoint Maze::getResurrectionCell() const 0224 { 0225 return m_resurrectionCell; 0226 } 0227 0228 #include "moc_maze.cpp"