1

i have been provided middleearth.h/cpp and was asked to make a makefile, doxyfile (which i did correctly) and a topological.cpp that works but has a small mistake in the output and i need help with that please.ill provide all three files and the text we use to test and the error.

cs2110 cs2150
cs2102 cs2150
cs1110 cs2110
cs3330 cs4414
cs2150 cs4414
cs2110 cs3330
cs1110 cs2102
0 0

enter image description here

middleearth.h

#ifndef MIDDLEEARTH_H
#define MIDDLEEARTH_H

#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <random>

using namespace std;

// see the comments in the lab11 write-up, or in middleearth.cpp

class MiddleEarth {
public:
    MiddleEarth(int xsize, int ysize, int num_cities, int seed);
    void print();
    void printTable();
    float getDistance(const string& city1, const string& city2);
    vector<string> getItinerary(unsigned int length);

private:
    int num_city_names, xsize, ysize;
    unordered_map<string, float> xpos, ypos;
    vector<string> cities;
    unordered_map<string, unordered_map<string, float>> distances;

    mt19937 gen; // Mersenne-Twister random number engine
};

#endif

middleearth.cpp

#include "middleearth.h"

#include <algorithm>
#include <array>
#include <cstdlib>
#include <cmath>

// New shuffle method that uses the Mersenne Twister engine
void shuffle (vector<string>::iterator first, vector<string>::iterator last, mt19937& g) {
    for (auto i=(last-first)-1; i>0; --i) {
        unsigned int n = (g() / (double) g.max())*distance(first,last);
        swap (first[i], first[n]);
    }
}

// The list of all the place names that we'll be using
const array<string, 40> all_city_names{
    // human towns, cities and strongholds
    "Bree",             // a human and hobbit town between the Shire and Rivendell
    "Isengard",         // the tower fortress where Saruman resided; Gandalf was imprisoned there.
    "Minas Tirith",     // capital of Gondor, the "white city"; home to Boromir, Denethor, and later, Aragorn
    "Osgiliath",        // city on the river Anduin; is at the other end of Pelennor Fields from M. Tirith
    "Edoras",           // the capital city of Rohan, where King Theoden resides
    "Helm's Deep",      // fortress of Rohan, it is where the people of Edoras fled to from the orc invasion
    "Dunharrow",        // a refuge of Rohan, it is where Elrond presents the sword to Aragorn in the movie
    // dwarf cities
    "Moria",            // the enormous dwarven underground complex that the Fellowship traveled through
    // elvish cities
    "Lothlorien",       // the elvish tree-city, home of Lady Galadriel and Lord Celeborn
    "Rivendell",        // the elvish city that is home to Lord Elrond
    "The Grey Havens",  // the port city on the western coast from which the elves travel westward
    // hobbit villages
    "Bucklebury",       // a Shire village, it has a ferry across the Brandywine River that the Hobbits use
    "Bywater",          // a Shire village, it is the site of the Battle of Bywater (removed from the movie)
    "Hobbiton",         // a Shire village, it is home to Bilbo and, later, Frodo
    "Michel Delving",   // a Shire village, it is the chief town of the Shire
    // Mordor places
    "Orodruin",         // Mount Doom in Mordor, it is where the Ring was made, and later, unmade
    "Barad-Dur",        // Sauron's fortress that was part castle, part mountain
    "Minas Morgul",     // formerly the Gondorian city of Minas Ithil; renamed when Sauron took it over
    "Cirith Ungol",     // the mountianous pass that Sam & Frodo went through; home of Shelob
    "Gorgoroth",        // the plains in Mordor that Frodo & Sam had to cross to reach Mount Doom
    // places that are not cities
    "Emyn Muil",        // the rocky region that Sam & Frodo climb through after leaving the Fellowship
    "Fangorn Forest",   // the forest where Treebeard (and the other Ents) live
    "Dagorlad",         // great plain/swamp between Emyn Muil & Mordor where a great battle was fought long ago
    "Weathertop",       // the tower between Bree and Rivendell where Aragorn and the Hobbits take refuge
    "Gladden Fields",   // this is where the Ring is lost in the River Anduin, after Isildur is ambushed and killed by Orcs
    "Entwash River",    // a river through Rohan, which flows through Fangorn Forest
    "River Isen",       // river through the Gap of Rohan; Theoden's son was slain in a battle here.
    "The Black Gate",   // huge gate to Mordor that Aragorn and company attack as the ring is destroyed
    "The Old Forest",   // a forest to the west of the Shire (adventures there were removed from the movie)
    "Trollshaws",       // area to the west of Rivendell that was home to the trolls that Bilbo met
    "Pelennor Fields",  // great plain between M. Tirith and Osgiliath; site of the Battle of M. Tirith
    "Hollin",           // the empty plains that the Fellowship crosses between Rivendell and Moria
    "Mirkwood",         // Legolas' forest home; Bilbo travels there in 'The Hobbit'.
    "Misty Mountains",  // the north-south moutain range that runs through Middle-earth
    "Prancing Pony",    // an inn in Bree where the hobbits tried to meet Gandalf, but meet Aragorn instead
    // places from the Hobbit book and movies
    "Laketown",         // also called Esgaorth, it is the town of men on the Long Lake near Erebor
    "Dale",             // the town of men outside Erebor, destroyed by Smaug long before the Hobbit story
    "Erebor",           // the Elvish name for the Lonely Mountain, where the dwarves had their fortress
    "Beorn's House",    // Beorn is the shape-shifter who shelters the dwarf party
    "Dol Guldur",       // fortress in Mirkwood where Sauron, as the Necromancer, hid during most of the Hobbit
};

// Iluvatar, the creator of Middle-Earth
MiddleEarth::MiddleEarth(int xsize, int ysize, int num_cities, int seed) {
    this->xsize = xsize;
    this->ysize = ysize;

    // set up the random number generator
    gen.seed(seed == -1 ? random_device{}() : seed);

    // count the number of cities in the array
    this->num_city_names = all_city_names.size();

    if (num_cities > num_city_names) {
        cout << "There are only " << num_city_names << " city names, so "
             << num_cities << " cities cannot be created." << endl;
        cout << "Exiting." << endl;
        exit(0);
    }

    if (num_cities < 5) {
        num_cities = 5;
    }

    // copy all the cities into a mutable vector
    this->cities = vector<string>(all_city_names.begin(), all_city_names.end());

    shuffle(cities.begin(), cities.end(), gen); // shuffle all the cities
    cities.erase(cities.begin() + num_cities, cities.end()); // then remove the ones we won't be using

    // compute random city positions
    for (auto city : cities) {
        xpos.emplace(city, (gen() / (double) gen.max()) * xsize);
        ypos.emplace(city, (gen() / (double) gen.max()) * ysize);
    }

    // compute the 2-d distance array
    // we assume that num_cities < xsize * ysize
    for (auto city1 : cities) {
        for (auto city2 : cities) {
            distances[city1].emplace(city2, sqrt((xpos[city2] - xpos[city1]) * (xpos[city2] - xpos[city1]) +
                                                 (ypos[city2] - ypos[city1]) * (ypos[city2] - ypos[city1])));
        }
    }
}

// The Mouth of Sauron!
// Prints out info on the created 'world'
void MiddleEarth::print() {
    cout << "there are " << num_city_names
         << " locations to choose from; we are using " << cities.size() << endl;
    cout << "they are: " << endl;
    for (auto city : cities) {
        cout << "\t" << city << " @ (" << xpos[city] << ", " << ypos[city]
             << ")" << endl;
    }
}

// Prints a tab-separated table of the distances,
// which can be loaded into Excel or similar
void MiddleEarth::printTable() {
    cout << "Table: " << endl << endl << "Location\txpos\typos\t";
    for (auto city : cities) {
        cout << city << "\t";
    }
    cout << endl;

    for (auto city1 : cities) {
        cout << city1 << "\t" << xpos[city1] << "\t" << ypos[city1] << "\t";
        for (auto city2 : cities) {
            cout << distances[city1][city2] << "\t";
        }
        cout << endl;
    }
}

// This method returns the distance between the two passed cities.
// If we assume that the hash table (i.e. the map) is O(1),
// then this method call is also O(1)
float MiddleEarth::getDistance(const string& city1, const string& city2) {
    return distances[city1][city2];
}

// Returns the list of cities to travel to.
// The first city is the original start point as well as the end point.
// The number of cities passed in does not include this start/end point
// (so there will be length+1 entries in the returned vector).
vector<string> MiddleEarth::getItinerary(unsigned int length) {
    // check parameter
    if (length >= cities.size()) {
        cout << "You have requested an itinerary of " << length
             << " cities; you cannot ask for an itinerary of more than length "
             << cities.size() - 1 << endl;
        exit(0);
    }

    length++; // to account for the start point

    // we need to make a deep copy of the cities vector
    vector<string> itinerary(cities.begin(), cities.end());

    // shuffle, erase unneeded ones, and return the itinerary
    shuffle(itinerary.begin(), itinerary.end(), gen);
    itinerary.erase(itinerary.begin() + length, itinerary.end());
    return itinerary;
}

topological.cpp

#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <list>
#include <stack>
#include <string>
#include <map>
using namespace std;
/**
@date 11/16/2020
*/
/** @brief
*/
class Graph 
{
  
  public:

    Graph(int vert); 
    /** @brief adds an edge to the list
    *  @param string v 
    *  @param string w 
    *  @param map<string, int> m
    * 
    */

    void addEdge(string v, string w, map<string, int> m); 
  
    void printSort(); 
  
  private:
    int vertices; 
    list<int> *myList; 
  
    void sort(int v, stack<int> &myStack, bool visited[]); 
    map<int, string> myMap; 
  };

 
Graph::Graph(int vert) {
  vertices = vert;
  myList = new list<int>[vertices];
}


void Graph::addEdge(string v, string w, map<string, int> m) {
  int loc1 = m[v];
  int loc2 = m[w];
  
  myMap[loc1] = v;
  myMap[loc2] = w;
  
  myList[loc1].push_back(loc2); 
}


void Graph::sort(int v, stack<int> &myStack, bool visited[]) {
  visited[v] = true;
  list<int>::iterator i;
  for(i = myList[v].begin(); i != myList[v].end(); ++i) {
    if(!visited[*i]) {
      sort(*i, myStack, visited);
    }
  }
  myStack.push(v);
}



void Graph::printSort() {
  stack<int> myStack;
  bool *visited = new bool[vertices];
  
  for(int i = 0; i < vertices; i++) {
    visited[i] = false;
  }
  
  for(int i = 0; i < vertices; i++) {
    if(visited[i] == false)
      sort(i, myStack, visited);
  }
  
  while(myStack.empty() == false) {
    int x = myStack.top();
    string output = myMap[x];
    cout << output << " ";
    myStack.pop();
  }
}


int main (int argc, char **argv) {
    
    if ( argc != 2 ) {
        cout << "Must supply the input file name as the one and only parameter" << endl;
        return 1;
    }
    
    ifstream file(argv[1], ifstream::binary);
    ifstream file1(argv[1], ifstream::binary);
    
    if ( !file.is_open() ) {
        cout << "Unable to open file '" << argv[1] << "'." << endl;
        return 1;
    }
    
    string s1, s2;
    int count = 0;
    list <string> edges;
   while(!file.eof()) {
      file >> s1;
      file >> s2;
      if(s1 == "0" && s2 == "0") {
  break;
      }
      edges.push_back(s1);
      edges.push_back(s2);
   }
   file.close();
   
    edges.sort();
    edges.unique();
    int size = edges.size();
    map<string, int> myMap;
    
    Graph myGraph(size);
    list<string>::iterator i;
    for(i = edges.begin(); i != edges.end(); i++) {
      string s = *i;
      myMap[s] = count;
      count++;
    }
    
      while(!file1.eof()) {
      file1 >> s1;
      file1 >> s2;
    if(s1 == "0" && s2 == "0") {
  break;
  }
      myGraph.addEdge(s1, s2, myMap);
    }

      myGraph.printSort();
      cout<<endl;
    file1.close();
    return 0;
}
David C. Rankin
  • 69,681
  • 6
  • 44
  • 72
kezah
  • 13
  • 5
  • What is the error? Where is the error? – Tanveer Badar Nov 17 '20 at 05:06
  • i have shared a screenhot, its printng cs3330 before cs2150, it should print cs2150 then cs3330 – kezah Nov 17 '20 at 05:11
  • 1
    Add `-Wshadow` as a compiler option and confirm that `xsize` and `ysize` that are shadowed between `middleearth.h` and `middleearth.cpp` are not the source of your error. And see [Why !.eof() inside a loop condition is always wrong.](https://stackoverflow.com/q/5605125/9254539) – David C. Rankin Nov 17 '20 at 05:13
  • middleearth.cpp/h shouldn't be modified at all, the only file that can be modified is topological.cpp – kezah Nov 17 '20 at 05:18
  • Well, your instructor needs to understand what shadowed variables are -- though in this case, they do not seem to be overwriting each other. Your reads with `while(!file1.eof())` are a problem. – David C. Rankin Nov 17 '20 at 05:20
  • isn't the issue with my topological.cpp? – kezah Nov 17 '20 at 05:21
  • Yes, your problem come after you declare `Graph myGraph(size)`. At that point, your `std::list edges` has the correct results, `cs1110 cs2102 cs2110 cs2150 cs3330 cs4414` Which you can check with a simple `for (const auto& n : edges) cout << " " << n; cout << '\n';` So I'm not sure what the rest of your code is doing -- you have your results in `edges`. – David C. Rankin Nov 17 '20 at 05:33
  • so what should i do for it to output cs2150 before cs3330? – kezah Nov 17 '20 at 05:36
  • Stop your code after `edges.unique();` and just `for (const auto& n : edges) cout << " " << n; cout << '\n';` – David C. Rankin Nov 17 '20 at 05:37
  • after edges.unique() i enter for (const auto& n : edges) cout << " " << n; cout << '\n'; and then return 0;? – kezah Nov 17 '20 at 05:38
  • edges.sort(); edges.unique(); for (const auto& n : edges) cout << " " << n; cout << '\n'; } myGraph.printSort(); cout< – kezah Nov 17 '20 at 05:45
  • you meant like this ^^? – kezah Nov 17 '20 at 05:45
  • Yes. after `edges.unique();` you can simply do. `bool first = true; for (const auto& n : edges) { if (!first) cout.put(' '); cout << n; first = false; } cout.put('\n');` (the `bool` added to just control the space before the first output). – David C. Rankin Nov 17 '20 at 05:49
  • after i add this after edges.unique(); i leave everything else as it is? – kezah Nov 17 '20 at 05:50
  • edges.sort(); edges.unique(); bool first = true; for (const auto& n : edges) { if (!first) cout.put(' '); cout << n; first = false; } cout.put('\n'); int size = edges.size(); map myMap; Graph myGraph(size); list::iterator i; for(i = edges.begin(); i != edges.end(); i++) { string s = *i; myMap[s] = count; count++; } – kezah Nov 17 '20 at 05:52
  • and i leave the whole rest under this^^? – kezah Nov 17 '20 at 05:52
  • i did that and i got another error of two lines, the first line is perfectly how i want it but the second line is as it was before, how ca i show u that? – kezah Nov 17 '20 at 05:56
  • I debugged your code and your sort function works wrongly. myList in Graph has only 2 and 1 items. myList[0] = 2 myList[1] = 1 In the stack, you change these variables as visited. You can analyze this section. I hope it will be helpful for you! – Sevki Kocadag Nov 17 '20 at 05:58

2 Answers2

0

You are confusing yourself. You have your solution in edges. There isn't a reason to read the data a second time. For example, you can simply output sorted/unique elements of edges, e.g. the modifications to your code are:

int main (int argc, char **argv) {
    
    if ( argc != 2 ) {
        cout << "Must supply the input file name as the one and only parameter" << endl;
        return 1;
    }
    
    ifstream file(argv[1], ifstream::binary);
//     ifstream file1(argv[1], ifstream::binary);
    
    if ( !file.is_open() ) {
        cout << "Unable to open file '" << argv[1] << "'." << endl;
        return 1;
    }
    
    string s1, s2;
//     int count = 0;
    list <string> edges;
    while(file >> s1 && file >> s2) {
        if(s1 == "0" && s2 == "0") {
        break;
    }
    edges.push_back(s1);
    edges.push_back(s2);
    }
    file.close();

    edges.sort();
    edges.unique();
//     int size = edges.size();
//     map<string, int> myMap;
    bool first = true;
    for (const auto& n : edges) {
        if (!first)
            cout.put(' ');
        cout << n;
        first = false;
    }
    cout.put('\n');
    
//     Graph myGraph(size);
//     list<string>::iterator i;
//     for(i = edges.begin(); i != edges.end(); i++) {
//       string s = *i;
//       myMap[s] = count;
//       count++;
//     }
//     
//     while(file1 >> s1 && file1 >> s2) {
//         if(s1 == "0" && s2 == "0") {
//     break;
//   }
//       myGraph.addEdge(s1, s2, myMap);
//     }
// 
//       myGraph.printSort();
//       cout<<endl;
//     file1.close();
    return 0;
}

(note: how while (!file.eof())) was replaced with while(file >> s1 && file >> s2))

Example Use/Output

With your sample data in dat/topological.txt, you would receive:

$ ./bin/topological dat/topological.txt
cs1110 cs2102 cs2110 cs2150 cs3330 cs4414

If you are having problems editing your code, then you can do things much easier with a std::set, e.g.

#include <iostream>
#include <fstream>
#include <string>
#include <set>

int main (int argc, char **argv) {
    
    if ( argc != 2 ) {
        std::cerr << "Must supply the input file name as the one and only parameter\n";
        return 1;
    }
    
    std::set<std::string> strset {};
    std::string s {};
    std::ifstream f (argv[1]);
    
    if (!f.good()) {
        std::cerr << "file open failed.\n";
        return 1;
    }
    
    while (f >> s && s != "0")
        strset.insert(s);
    
    bool first = true;
    for (const auto& unique : strset) {
        if (!first)
            std::cout.put(' ');
        std::cout << unique;
        first = false;
    }
    std::cout.put('\n');
}

(same answer)

David C. Rankin
  • 69,681
  • 6
  • 44
  • 72
  • I guess you found the `returm` problem in your image `:)` Good luck with your coding! Also, your exercise, seems like at multi-part problem. This part of your project was to find the unique and sorted strings in your file. Your `Graph` and topography mapping will likely build upon this. – David C. Rankin Nov 17 '20 at 06:17
0

This is when i used the main you gave me: enter image description here

This is when i added (Yes. after edges.unique(); you can simply do. bool first = true; for (const auto& n : edges) { if (!first) cout.put(' '); cout << n; first = false; } cout.put('\n');): enter image description here

the first line on output is correct, i dont want the line under it

kezah
  • 13
  • 5
  • i actually fixed it (had to declare (return) cuz we using doxyfile now thank you so much! – kezah Nov 17 '20 at 06:07