// vim: set ts=3 sw=3 et tw=80: /* Assignment 4 - Chess paths * Claudio Maggioni * * External sources used: * - cppreference.com * - DFS wikipedia implementation (adapted). * * The flag DEBUG, if defined, activates some debug messages printe on stdout. * This is disabled to comply with tests. */ #include "roadmap.h" #include #include #include #include #include using namespace std; class ConcreteRoadMap : public AbstractRoadMap { private: map< string, set > adj; /* * Adds in the map for key city1 a new set with city2 inside if there is * no prior set, otherwise it appends city2 into the existing set */ void addPair(const string& city1, const string& city2) { this->adj[city1].insert(city2); } public: ConcreteRoadMap() : adj() {}; void addRoad(const string& city1, const string& city2) override; void addRoad(const vector& cities) override; void clear() override; int neighborCountForCity(const string& city) const override; bool hasLoop() const override; bool reachable(const string& c1, const string& c2) const override; int countIslands() const override; }; void ConcreteRoadMap::addRoad(const string& city1, const string& city2) { addPair(city1, city2); addPair(city2, city1); } void ConcreteRoadMap::addRoad(const vector& cities) { for (size_t i = 0; i < cities.size() - 1; i++) { addRoad(cities[i], cities[i + 1]); } } void ConcreteRoadMap::clear() { adj.clear(); } int ConcreteRoadMap::neighborCountForCity(const string& city) const { auto i = this->adj.find(city); if (i == adj.end()) return -1; return i->second.size(); } bool ConcreteRoadMap::hasLoop() const { stack< std::pair > s; set discovered; bool search_comp; for (auto itr = adj.begin(); itr != adj.end(); ++itr) { search_comp = true; s.push(std::pair(itr->first, itr->first)); while (!s.empty()) { const std::pair v = s.top(); #if DEBUG std::cout << "Front is: " << v.first << " with parent " << v.second << "\n"; #endif s.pop(); if (discovered.find(v.first) == discovered.end()) { search_comp = false; discovered.insert(v.first); const auto i = this->adj.find(v.first); const auto set = i->second; for (auto j = set.begin(); j != set.end(); ++j) { if (*j != v.second) { #if DEBUG cout << "Neighbor: " << *j << " parent: " << v.first << "\n"; #endif s.push(std::pair(*j, v.first)); } } } else if (!search_comp) { #if DEBUG cout << v.first << " is discovered\n"; #endif return true; } } } return false; } bool ConcreteRoadMap::reachable(const string& c1, const string& c2) const { if (adj.find(c1) == adj.end() || adj.find(c2) == adj.end()) { return false; } deque s; set discovered; s.push_back(c1); while (!s.empty()) { const string v = s.front(); if (v == c2) return true; s.pop_front(); discovered.insert(v); const auto i = this->adj.find(v); const auto set = i->second; for (auto j = set.begin(); j != set.end(); ++j) { if (discovered.find(*j) == discovered.end()) { s.push_back(*j); } } } return false; } int ConcreteRoadMap::countIslands() const { int islands = 0; bool first; stack< std::pair > s; set discovered; for (auto itr = adj.begin(); itr != adj.end(); ++itr) { s.push(std::pair(itr->first, itr->first)); first = true; while (!s.empty()) { const std::pair v = s.top(); #if DEBUG std::cout << "Front is: " << v.first << " with parent " << v.second << "\n"; #endif s.pop(); if (discovered.find(v.first) == discovered.end()) { if (first) { islands++; } discovered.insert(v.first); const auto i = this->adj.find(v.first); const auto set = i->second; for (auto j = set.begin(); j != set.end(); ++j) { if (*j != v.second) { #if DEBUG cout << "Neighbor: " << *j << " parent: " << v.first << "\n"; #endif s.push(std::pair(*j, v.first)); } } } else { #if DEBUG cout << v.first << " is discovered\n"; #endif } first = false; } } return islands; } AbstractRoadMap* createRoadMap() { return new ConcreteRoadMap(); }