AMERICAN UNIVERSITY OF SCIENCE & TECHNOLOGY FACULTY OF ARTS AND SCIENCES CSI/ICT Department CSI-391 – Data Structures and Algorithms Maze solving By Ahmad Dib -12200384Rayen Kamal -12200426Hussein Mahmoud -12202047Adam Kanso-12212035Submitted to Dr. David Semaan Achrafieh, Lebanon January,8,2023 P a g e i | 13 Abstract Maze Solver This project addresses a program that we developed in C++. The making of this code was a good and fun way to practice the skills and knowledge we learned throughout the Data Structures course. This research paper targets university students. It presents the objectives of the app, a brief explanation and introduction, a detailed account of the design and procedures included in the creation of this app as well as a description of the problems faced and proposed solutions. P a g e 2 | 13 Table of Contents Abstract ......................................................................................................................................... 2 Table of Contents .......................................................................................................................... 3 I. Introduction ........................................................................................................................ 4 II. Objectives............................................................................................................................ 4 III. Background ........................................................................................................................ 4 IV. Program and Problem Definition ..................................................................................... 4 V. Problems Faced and Solutions .......................................................................................... 5 VI. Code With Explanation .................................................................................................... 5 VII. Conclusion………………………………………………………………14 P a g e 3 | 13 I. Introduction We wanted to apply what we learned in Data Structures to develop our first App that is a maze solving program coded to show us both the traversal stack and queues (BFS and DFS) from the entrance to the exit. II. Objectives 1- Create an app while applying the skills we acquired during our sessions. 2- Using DFS get the app to show the traversal stack. 3- Using BFS get the app to show the traversal queue. III. Background We were asked to create a C++ Maze Solver for our final project in our Data Structures course. We found that creating this app using C++ is a fun and creative way of applying what we learned throughout the semester, in addition to using external sources such as the internet to aid us in completing this project and further our understanding of coding. IV. Program and Problem Definition The project is addressing the problem which is creating a mistake free and efficient app that shows you both the traversal stack for a maze using the DFS method, and the traversal queue for the BFS method going from the entrance to the exit. P a g e 4 | 13 V. Problems Faced and Solutions A. Our first error was us following the old map where nodes 1 and 12 were neighbors. B. We fell into syntax errors that are normal while coding and were easy to fix. C. The start node was initialized in a wrong way at first which caused a problem, and it was fixed by initializing the node start_pos at n1. VI. Code With Explanation #include <iostream> #include <queue> #include <unordered_map> #include <stack> // We create the structure of the nodes in the graph struct Node { // We assign a value to the node. int value; // The list of neighbors of the node using a vector std: vector<Node*> neighbors; bool exit = false; }; P a g e 5 | 13 // We created a structure for the graph that will hold the nodes. class Graph { public: // The list of nodes in the graph. std::vector<Node*> nodes; // BFS Function void BFS(Node* start) { // Create a queue to hold the nodes that we need to visit. std::queue<Node*> q; // Create a map to track which nodes have been visited. std::unordered_map<Node*, bool> visited; // Add the start node to the queue and mark it as visited. q.push(start); visited[start] = true; // While the queue is not empty... while (!q.empty()) { // Get the next node to visit. Node* current = q.front(); //Pop every node the current visits q.pop(); // Print the value of the current node. std::cout << current->value << std::endl; // If the current gets to the exit the loop breaks if (current->exit) { break; } P a g e 6 | 13 // Add all of the unvisited neighbors of the current node to the queue. for (Node* neighbor : current->neighbors) { if (!visited[neighbor]) { q.push(neighbor); visited[neighbor] = true; } } } }; // This function performs a depth-first search starting from the given start node. void DFS(Node* start) { // Create a map to track which nodes have been visited. std::unordered_map<Node*, bool> visited; // Create a stack to hold the nodes that we need to visit. std::stack<Node*> s; // Add the start node to the stack and mark it as visited. s.push(start); visited[start] = true; // While the queue is not empty... while (!s.empty()) { // Get the next node to visit. Node* curr = s.top(); //Pop every node the current visits s.pop(); // Print the value of the current node. std::cout << curr->value << std::endl; // If the current gets to the exit the loop breaks if (curr->exit) { P a g e 7 | 13 break; } // Add all of the unvisited neighbors of the current node to the stack. for (Node* neighbor : curr->neighbors) { if (!visited[neighbor]) { s.push(neighbor); visited[neighbor] = true; } } } // Print the value of the start node. } }; int main() { // Create a graph. Graph g; // Create the nodes. Node* n1 = new Node{ 1 }; Node* n2 = new Node{ 2 }; Node* n3 = new Node{ 3 }; Node* n4 = new Node{ 4 }; Node* n5 = new Node{ 5 }; Node* n6 = new Node{ 6 }; Node* n7 = new Node{ 7 }; Node* n8 = new Node{ 8 }; P a g e 8 | 13 Node* n9 = new Node{ 9 }; Node* n10 = new Node{ 10 }; Node* n11 = new Node{ 11 }; Node* n12 = new Node{ 12 }; //Push the nodes to the graph. g.nodes.push_back(n1); g.nodes.push_back(n2); g.nodes.push_back(n3); g.nodes.push_back(n4); g.nodes.push_back(n5); g.nodes.push_back(n6); g.nodes.push_back(n7); g.nodes.push_back(n8); g.nodes.push_back(n9); g.nodes.push_back(n10); g.nodes.push_back(n11); g.nodes.push_back(n12); // Assign the neighbors to each other in the graph. n1->neighbors.push_back(n2); n1->neighbors.push_back(n10); n2->neighbors.push_back(n3); n2->neighbors.push_back(n9); n2->neighbors.push_back(n1); n3->neighbors.push_back(n2); n3->neighbors.push_back(n4); n4->neighbors.push_back(n3); n4->neighbors.push_back(n9); n4->neighbors.push_back(n5); n5->neighbors.push_back(n4); P a g e 9 | 13 n5->neighbors.push_back(n6); n6->neighbors.push_back(n5); n6->neighbors.push_back(n9); n6->neighbors.push_back(n7); n7->neighbors.push_back(n6); n7->neighbors.push_back(n9); n7->neighbors.push_back(n8); n8->neighbors.push_back(n7); n8->neighbors.push_back(n12); n8->neighbors.push_back(n11); n9->neighbors.push_back(n10); n9->neighbors.push_back(n11); n9->neighbors.push_back(n2); n9->neighbors.push_back(n4); n9->neighbors.push_back(n6); n9->neighbors.push_back(n7); n10->neighbors.push_back(n9); n10->neighbors.push_back(n11); n10->neighbors.push_back(n1); n11->neighbors.push_back(n8); n11->neighbors.push_back(n12); n11->neighbors.push_back(n9); n11->neighbors.push_back(n10); n12->neighbors.push_back(n8); // We create the main page that will welcome the user and will ask him what option does he want. std::cout << "Pick entrance/exit or play defaulft? 0:Default 1:pick" << std::endl; // Initialize picker to 0. bool picker = 0; // Enter choice. P a g e 10 | 13 std::cin >> picker; // If chose Default the code follows 12 as exit. if (!picker) { n12->exit = true; // If chose default bool picker2 = 0; // Code asks whether user wants it to follow DFS or BFS. std::cout << "Pick bfs/dfs? 0:dfs 1:bfs" << std::endl; // Enter choice. std::cin >> picker2; // If chose DFs follow DFS function. if (!picker2) { g.DFS(n1); return 0; } // Else follow BFS function. else { g.BFS(n1); return 0; } } // If chose pick. else { int finish = 12;//by default int start; Node* start_pos = n1; // Ask the user to choose the starting node. std::cout << "pick the start cell:" << std::endl; P a g e 11 | 13 // Enter number of node. std::cin >> start; // Ask the user to choose the finishing node. std::cout << "pick the finish cell:" << std::endl; // Enter number of node. std::cin >> finish; for (auto node : g.nodes) { // The number picked after the question of what node to finish with becomes the exit. if (node->value == finish) { node->exit = true; } } for (auto node : g.nodes) { // The number picked after the question of what node to start with becomes the entrance. if (node->value == start) { start_pos = node; } } // What function to follow after choosing the finish and start nodes. std::cout << "Pick bfs/dfs? 0:dfs 1:bfs" << std::endl; bool picker3; // Enter choice. std::cin >> picker3; // If chose 0 follow DFS. if (!picker3) { g.DFS(start_pos); } //Else perform BFS. else { P a g e 12 | 13 g.BFS(start_pos); } } } VII. Conclusion In the end after we altered the code many times and solved all the problems that we faced we were finally able to create a working and successful code that gave us the choice to either perform DFS or BFS on the normal declared maze where 1 was the entrance and 12 was the exit, in addition, to performing these codes but with the ability to choose freely any starting and finishing node in the maze. P a g e 13 | 13