diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39a43f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +*.exe +*.vcxproj.user +*.obj +*.log +*.pdb +*.idb +*.tlog +*.lastbuildstate +*.ilk +*.exe.recipe +*.vcxproj +*.sln +*.vcxproj.filters \ No newline at end of file diff --git a/Practise_18.11.20/Practise_18.11.20/MCell.h b/Practise_18.11.20/Practise_18.11.20/MCell.h new file mode 100644 index 0000000..7592aba --- /dev/null +++ b/Practise_18.11.20/Practise_18.11.20/MCell.h @@ -0,0 +1,12 @@ +#pragma once + +class MCell { +public: + bool down() const { return m_down; } + bool right() const { return m_right; } + friend class Maze; +private: + MCell() = default; + bool m_down = false; + bool m_right = false; +}; diff --git a/Practise_18.11.20/Practise_18.11.20/MTreeNode.cpp b/Practise_18.11.20/Practise_18.11.20/MTreeNode.cpp new file mode 100644 index 0000000..5808f75 --- /dev/null +++ b/Practise_18.11.20/Practise_18.11.20/MTreeNode.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include "MTreeNode.h" +using namespace std; + +MTreeNode* MTreeNode::beginTree(int i, int j) { + MTreeNode* node = new MTreeNode(nullptr); + node->m_i = i; + node->m_j = j; + return node; +} + +MTreeNode::MTreeNode(MTreeNode* parent) { + m_parent = parent; + if (parent) m_distance = parent->m_distance + 1; +} + +MTreeNode::~MTreeNode() { + for (auto ptr : m_children) + delete ptr; +} + +bool MTreeNode::addChild(int i, int j) { + if (abs(i - m_i + j - m_j) != 1) + return false; + + for (auto &child : m_children) + if (child->m_i == i && child->m_j == j) + return false; + m_children.push_back(new MTreeNode(this)); + m_children.back()->m_i = i; + m_children.back()->m_j = j; + return true; +} + +MTreeNode* MTreeNode::hasChild(int i, int j) const{ + for (auto child : m_children){ + if (child->m_i == i && child->m_j == j) + return child; + } + return nullptr; +} + +//, +const MTreeNode* MTreeNode::searchNode(const int i, const int j) const{ + queue nodes; + auto node = searchRoot(this); + while (true) + { + if (node->m_i == i && node->m_j == j) return node; + for (const auto child : node->m_children) { + if (child->i() == i && child->j() == j) + return child; + nodes.push(child); + } + if (nodes.size() == 0) + break; + node = nodes.front(); + nodes.pop(); + } +} + +// +const MTreeNode* MTreeNode::searchRoot(const MTreeNode* node) const{ + queue nodes; + MTreeNode* parent = node->m_parent; + if (!parent) + return node; + else { + while (true) { + MTreeNode* temp = parent->m_parent; + if (!temp) break; + parent = temp; + } + return parent; + } +} diff --git a/Practise_18.11.20/Practise_18.11.20/MTreeNode.h b/Practise_18.11.20/Practise_18.11.20/MTreeNode.h new file mode 100644 index 0000000..c1b876b --- /dev/null +++ b/Practise_18.11.20/Practise_18.11.20/MTreeNode.h @@ -0,0 +1,25 @@ +#pragma once +#include + +class MTreeNode +{ +public: + ~MTreeNode(); + int i() const { return m_i; } + int j() const { return m_j; } + int distance() const { return m_distance; } + int childCount() const { return m_children.size(); } + bool addChild(int i, int j); + const MTreeNode* parent() const { return m_parent; } + MTreeNode* hasChild(int i, int j) const; + const MTreeNode* child(int i) const { return m_children[i]; } + static MTreeNode* beginTree(int i, int j); + const MTreeNode* searchNode(const int i, const int j) const; + const MTreeNode* searchRoot(const MTreeNode* node) const; +private: + int m_i, m_j = 0; + int m_distance = 0; + MTreeNode* m_parent = nullptr; + std::vector m_children; + MTreeNode(MTreeNode* parent); +}; diff --git a/Practise_18.11.20/Practise_18.11.20/Maze.cpp b/Practise_18.11.20/Practise_18.11.20/Maze.cpp new file mode 100644 index 0000000..69e32d0 --- /dev/null +++ b/Practise_18.11.20/Practise_18.11.20/Maze.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include "Maze.h" +#include +using namespace std; + +enum MazeElem { + Up = 1 << 0, + Left = 1 << 1, + Down = 1 << 2, + Right = 1 << 3, + UpLeft = Up + Left, + UpDown = Up + Down, + UpRight = Up + Right, + LeftDown = Left + Down, + LeftRight = Left + Right, + RightDown = Right + Down, + UpLeftDown = Up + Left + Down, + UpLeftRight = Up + Left + Right, + UpDownRight = Up + Down + Right, + LeftDownRight = Left + Down + Right, + AllDirection = Up + Left + Down + Right, +}; +static map m_dict = { {AllDirection, char(197)}, {UpLeftDown, char(180)}, {UpLeftRight, char(193)}, + {UpDownRight, char(195)}, {LeftDownRight, char(194)}, {UpLeft, char(217)}, + {UpDown, char(179)}, {UpRight, char(192)}, {LeftDown, char(191)}, + {LeftRight, char(196)}, {RightDown, char(218)}, {Up, '0'}, {Down, '0'}, {Left, '0'}, {Right, '0'}, {0, '0'} +}; + +Maze::Maze(int n, int m) { + m_width = m; + m_height = n; + m_field = new MCell[m * n]; +} + +Maze::~Maze() { delete[] m_field; } + +const MCell& Maze::cell(int i, int j) const { + assert(i >= 0 && i < m_height && j >= 0 && j < m_width); + return m_field[i * m_width + j]; +} + +bool Maze::checkConnection(int i1, int j1, int i2, int j2) const { + assert(i1 == i2 || j1 == j2); + if ((abs(i1 - i2) + abs(j1 - j2) != 1)) + return false; + if (j2 < 0 || j2 >= m_width || i2 < 0 || i2 >= m_height) + return false; +} + +bool Maze::hasConnection(int i1, int j1, int i2, int j2) const { + if (!checkConnection(i1, j1, i2, j2)) + return false; + const int ind1 = min(i1, i2); + const int ind2 = min(j1, j2); + if (i1 == i2) { + return m_field[ind1 * m_width + ind2].right(); + } + else if (j2 == j1) { + return m_field[ind1 * m_width + ind2].down(); + } +} + +bool Maze::makeConnection(int i1, int j1, int i2, int j2) { + if (!checkConnection(i1, j1, i2, j2)) + return false; + const int ind1 = min(i1, i2); + const int ind2 = min(j1, j2); + if (i1 == i2) { + m_field[ind1 * m_width + ind2].m_right = true; + return true; + } + else if (j1 == j2) { + m_field[ind1 * m_width + ind2].m_down = true; + return true; + } +} + +bool Maze::removeConnection(int i1, int j1, int i2, int j2) { + if (!checkConnection(i1, j1, i2, j2)) + return false; + int ind1 = min(i1, i2); + int ind2 = min(j1, j2); + if (i1 == i2) { + bool res = m_field[ind1 * m_width + ind2].m_right; + m_field[ind1 * m_width + ind2].m_right = false; + return res; + } + else if (j2 == j1) { + bool res = m_field[ind1 * m_width + ind2].m_down; + m_field[ind1 * m_width + ind2].m_down = false; + return res; + } +} + +void Maze::printMaze() const { + for (int n = 0; n < m_width * m_height; ++n) { + int i = n / m_width; + int j = n % m_width; + int res = m_field[n].down() << 2 | m_field[n].right() << 3; + if (i - 1 >= 0) + res += m_field[(i - 1) * m_width + j].down() << 0; + if (j - 1 >= 0) + res += m_field[i * m_width + j - 1].right() << 1; + + assert(typeid(m_dict.find(res)->second) == typeid(char)); + cout << m_dict.find(res)->second; + + if (j + 1 == m_width) + cout << endl; + } +} diff --git a/Practise_18.11.20/Practise_18.11.20/Maze.h b/Practise_18.11.20/Practise_18.11.20/Maze.h new file mode 100644 index 0000000..d5d698a --- /dev/null +++ b/Practise_18.11.20/Practise_18.11.20/Maze.h @@ -0,0 +1,18 @@ +#pragma once +#include "MCell.h" + +class Maze { +public: + Maze(int n, int m); + ~Maze(); + const MCell& cell(int i, int j) const; + bool checkConnection(int i1, int j1, int i2, int j2) const; + bool hasConnection(int i1, int j1, int i2, int j2) const; + bool makeConnection(int i1, int j1, int i2, int j2); + bool removeConnection(int i1, int j1, int i2, int j2); + void printMaze() const; +private: + MCell* m_field = nullptr; + int m_width = 0; + int m_height = 0; +}; diff --git a/Practise_18.11.20/Practise_18.11.20/Practise_18.11.20.cpp b/Practise_18.11.20/Practise_18.11.20/Practise_18.11.20.cpp new file mode 100644 index 0000000..3995953 --- /dev/null +++ b/Practise_18.11.20/Practise_18.11.20/Practise_18.11.20.cpp @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include "MTreeNode.h" +#include "MCell.h" +#include "Maze.h" +#include +using namespace std; + +void buildFullMaze(Maze& iMaze, const MTreeNode* tree); +void BuildMaze2(Maze& maze, const int maze_size); +void BuildMaze1(Maze& maze, const int maze_size); +void BuildTree(MTreeNode* node, const int width, const int height); +void BuildTreeForMaze2(Maze& maze, const int maze_size, MTreeNode* node); +void PrintTreeInfo(const MTreeNode* tree, const int width, const int height); +vector GetRandCoordinates(const int width, const int height); + +void PrintTreeInfo(const MTreeNode* tree, const int width, const int height) { + int sum_weights = 0; + int max_weight = 0; + queue nodes; + vector> to_print(height); + for (auto& vctr : to_print) + vctr = vector(width); + for (int p = 0; p < width * height; ++p) { + int i = tree->i(); + int j = tree->j(); + sum_weights += tree->distance(); + max_weight = max(tree->distance(), max_weight); + to_print[i][j] = to_string(tree->distance()); + for (int ind = 0; ind < tree->childCount(); ++ind) + nodes.push(tree->child(ind)); + if (p + 1 == width * height) break; + tree = nodes.front(); + nodes.pop(); + } + const int max_len = size(to_string(max_weight)); + for (auto& vctr : to_print) { + for (auto& str : vctr) + cout << setw(max_len + 1) << str; + cout << endl; + } + const int average_weight = sum_weights / (1. * width * height); + cout << endl << "The maximum weight of tree vertices: " << max_weight << endl; + cout << endl << "The average weight of the vertices: " << average_weight << endl; +} + +void buildFullMaze(Maze& iMaze, const MTreeNode* tree) { + queue nodes; + while (true) { + int t_i = tree->i(); + int t_j = tree->j(); + for (int ind = 0; ind < tree->childCount(); ++ind) { + const MTreeNode* child = tree->child(ind); + iMaze.makeConnection(t_i, t_j, child->i(), child->j()); + nodes.push(child); + } + if (nodes.size() == 0) + break; + tree = nodes.front(); + nodes.pop(); + } +} + +vector GetRandCoordinates(const int width, const int height) { + if (width == 0 || height == 0) + return { 0, 0 }; + srand(time(NULL)); + int flag = rand() % 4 + 1; + switch (flag) { + case(1): + return { 0, rand() % width }; + case(2): + return { rand() % height, 0 }; + case(3): + return { height - 1, rand() % width }; + default: + return { rand() % height, width - 1 }; + } +} + +void BuildTree(MTreeNode* tree, const int width, const int height) { + queue nodes; + while (true) { + int n_i = tree->i(); + int n_j = tree->j(); + for (int i = -1; i < 2; ++i) + for (int j = -1; j < 2; ++j) { + if ((i != 0 && j != 0) || (i == 0 && j == 0)) + continue; + if (n_i + i < 0 || n_i + i >= height || n_j + j < 0 || n_j + j >= width) + continue; + int child_i = n_i + i; + int child_j = n_j + j; + if (!tree->searchNode(child_i, child_j)) { + tree->addChild(child_i, child_j); + MTreeNode* child = tree->hasChild(child_i, child_j); + nodes.push(child); + } + } + if (nodes.size() == 0) + break; + tree = nodes.front(); + nodes.pop(); + } +} + +void BuildMaze2(Maze& maze, const int maze_size) { + int ind_right = 0; + int ind_down = 0; + for (int i = 0; i < maze_size - 1; ++i) { + int count = i + 2; + for (int j = 0; j < maze_size; ++j) { + if (ind_right == j) { + ind_right++; + maze.makeConnection(i, j, i, j + 1); + } + if (ind_down == i && j < count) { + maze.makeConnection(i, j, i + 1, j); + } + } + ind_down++; + ind_right = ind_down; + } +} + +void BuildMaze1(Maze& maze, const int maze_size) { + int ind_right = 0; + int ind_down = 1; + for (int i = 0; i < maze_size; ++i) { + for (int j = 0; j < maze_size; ++j) { + if (i == maze_size - 1 && j == maze_size - 1) { + break; + } + if (i == ind_right && j == ind_right) { + maze.makeConnection(i, j, i, j + 1); + } + if (i == ind_right && j == ind_down) { + maze.makeConnection(i, j, i + 1, j); + } + } + ++ind_down; + ++ind_right; + } +} + +void BuildTreeForMaze2(Maze& maze, const int maze_size, MTreeNode* node) { + vector strings; + queue nodes; + while (true) { + int i = node->i(); + int j = node->j(); + if (maze.hasConnection(i, j, i + 1, j)) { + node->addChild(i + 1, j); + nodes.push(node->hasChild(i + 1, j)); + } + if (maze.hasConnection(i, j, i, j + 1)) { + node->addChild(i, j + 1); + nodes.push(node->hasChild(i, j + 1)); + } + if (i < strings.size()) + strings[i] += to_string(node->distance()) + ' '; + else + strings.push_back(to_string(node->distance()) + ' '); + + if (nodes.size() == 0) + break; + node = nodes.front(); + nodes.pop(); + } + for (auto& str : strings) + cout << str << endl; +} + +int main() +{ + const int maze_size = 5; + Maze maze1(maze_size, maze_size); + BuildMaze1(maze1, maze_size); //Построение простого лабиринта-лесенки + cout << "Maze #1:" << endl << endl; + maze1.printMaze(); //Печать лабиринта-лесенки + + Maze maze2(maze_size, maze_size); + BuildMaze2(maze2, maze_size); //Построение лабиринта паутинки-лесенки + cout << endl << "Maze #2:" << endl << endl; + maze2.printMaze(); //Печать лабиринта паутинки-лесенки + + MTreeNode* start_node = MTreeNode::beginTree(0, 0); + cout << endl << "Node tree for Maze #2:" << endl << endl; + BuildTreeForMaze2(maze2, maze_size, start_node); //Построение и печать дерева обхода для лабиринта паутинки-лесенки + delete start_node; + + int width, height; + cout << endl << "Enter the height and width of the maze separated by a space: "; + cin >> height >> width; //Считывание размеров случайного лабиринта + + auto start_coordinates = GetRandCoordinates(width, height);//Функция для получения произвольных координат на границе лабиринта + MTreeNode* tree = MTreeNode::beginTree(start_coordinates[0], start_coordinates[1]); + BuildTree(tree, width, height); //Построение дерева для случайного лабиринта заданного размера + Maze maze3(height, width); + buildFullMaze(maze3, tree); //Создание лабиринта по дереву + cout << endl << "Maze #3:" << endl << endl; + maze3.printMaze(); //Печать случайного лабиринта заданного размера + cout << endl << "Node tree for random maze:" << endl << endl; + PrintTreeInfo(tree, width, height); //Печать весов дерева на экран построчно и пеать информации о вершинах + + return 0; +}