1. Overview

In this project you will:

  • Implement a linked-list data structure,
  • Use dynamic memory allocation to create new objects,
  • Practice using C++ class syntax,
  • Practice object-oriented thinking.

2. Background

A container ship is type of cargo ship that carries all of its load in truck-size intermodal containers, in a technique called containerization. Container ships are a common means of commercial intermodal freight transport and now carry most seagoing non-bulk cargo. Today, about 90% of non-bulk cargo worldwide is transported by container ships. Container ships now rival crude oil tankers and bulk carriers as the largest commercial seaborne vessels.

For this project, we are going to be designing a tool that allows us to create routes for container ships on the eastern coast of the US. There is a provided file of port information, and we can create routes for each of the container ships to travel from port to port.

3. Assignment Description

Your assignment is to build an application that will allow the user to create multiple routes. Each route would be made up of several ports.

4. Requirements:

Initially, you will have to use the following files Port.h, Route.h, Navigator.h, makefile, proj3.cpp, and one input file (proj3_data.txt).

  • The project must be completed in C++. You may not use any libraries or data structures that we have not learned in class. No breaks (except in switch statements), continues, or exit(). Libraries we have learned include < iostream >, < fstream >, < iomanip >, < vector >, < cstdlib >, < time.h >, < cmath >, < list >,and < string >. You should only use namespace std.
  • You must use the function prototypes as outlined in the Port.h, Route.h and Navigator.h header file. Do not edit the header files.
  • There is one input file of ports to use including proj3_data.txt. You can see how the input file is organized in figure 2 below.Sample input File:see image.
  • The node class is called Port and contains five pieces of data: The name of the port (m_name), the location of the port (m_location), the degrees north of the port (m_north), the degrees west of the port (m_west), and a pointer to the next port (m_next). All variables in the Port class are private and must be accessed using getters.
    • Port (default constructor) - creates a "New Port" from a New Location with north and west of 0 and m_next = nullptr;
    • Port (Overloaded constructor) - uses data passed to populate member variables
    • Setters and Getters (may not be used explicitly but need to be implemented)
    • Overloaded << operator - Allows user to print a specific node. Provided in .h file.
  • The linked list class is called Route and contains four pieces of data: A name for the route (m_name), a Port pointer tracking the front of the Route (m_head), a Port pointer tracking the end of the Route (m_tail), and an integer tracking the size of the Route (m_size).
    • Route (Default) - creates a new route with name of "Test" and pointers = nullptr and m_size = 0;
    • ~Route - Destructs the whole route
    • InsertEnd - Inserts a new Port into the route at the end of the route.
    • SetName() - May not be used explicitly but you must implement. Updates the name of the route based on the string passed.
    • UpdateName() - Used to update the name of the route based on the name of the first port and the last port of the route. So, if the first port was Baltimore and the last port was Boston, the name would be Baltimore to Boston.
    • Getters (size and name) - May not be used explicitly in project but you must implement them.
    • ReverseRoute - Reverses the route so that the ports are in reverse order. Can be called multiple times. Must rotate ports in the route (cannot update just data).
    • GetData - Returns a port pointer at a specific index. Passed the number of the node you would like to return from 0 to size-1. May not be used explicitly in project but you must implement it.
    • RemovePort - Removes a port from an existing route. Passed the index of the port to remove. Hint: Don't forget about the special cases (first node, last node, or middle node). Dont forget to update m_tail.
  • The class managing the loading of files, the user input, and the routes is called Navigator. It has three pieces of data: a vector to hold the Routes (m_routes), a vector to hold the Ports (m_ports), and a string holding the name of the input file (m_fileName).
    • Navigator(Overloaded) - Creates a new Navigator object that is passed the file name to load.
    • ~Navigator - Destructor for the manager
    • Start - Reads in the file and calls the main menu.
    • ReadFile - Reads in the file and dynamically allocates ports and inserts them into m_ports.
    • MainMenu - Lists each of the options: 1. Create New Route, 2. Display Route, 3. Remove Port from Route, 4. ReverseRoute and 5. Exit. Calls the corresponding functions as needed.
    • DisplayPorts - Displays numbered list of each port in m_ports. Uses provided << operator.
    • DisplayRoute - Checks to see if there are any routes to display. If there are, asks user which route to display using ChooseRoute. Calls DisplayRoute in Route. Shows total miles in route.
    • ChooseRoute - Asks the user which route they would like to work with. Returns index of route chosen.
    • ReverseRoute - Allows user to choose one route to reverse using ChooseRoute.
    • InsertNewRoute - Allows user to insert dynamically allocated new route into m_routes. User continues to add ports (no limit) until they enter a -1. Sets the name of the new route to the name of the first port and the name of the last port as in "Boston to Camden".
    • RemovePortFromRoute - Allows user to remove a port from an already existing route in m_routes. User selects a port to remove from numbered list. Will update the name of the route to be the name of the first port and the name of the last port as in "Boston to Camden".
    • RouteDistance - Iterates over each port in a specific route in m_routes and uses the provided CalcDistance to calculate the distance between two ports. Calls CalcDistance for port 1 to port 2, then port 2 to port 3, and so on until it reaches the end of the route.
    • CalcDistance - Provided (do not edit). Used to calculate the distance between two points when provided with the north and west for each point.
  • All user inputs will be assumed to be the correct data type. For example, if you ask the user for an integer, they will provide an integer.
  • Regardless of the sample output below, all user input must be validated. If you ask for a number between 1 and 5 with the user entering an 8, the user should be re-prompted.

5. Sample Input and Output

5.1. Sample Run

A normal run of the compiled code would look like this with user input highlighted in blue:

[linux2 proj3]$ make run
./proj3 proj3_data.txt

***Navigator***

Opened File
Ports loaded: 36
What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit
1
1. Baltimore, Maryland
2. Boston, Massachusetts
**REMOVED FOR DOCUMENT LENGTH**
35. Wilmington - Delaware, Delaware
36. Wilmington - North Carolina, North Carolina
Enter the number of the port to add to your Route: (-1 to end)
1
Enter the number of the port to add to your Route: (-1 to end)
2
Enter the number of the port to add to your Route: (-1 to end)
3
Enter the number of the port to add to your Route: (-1 to end)
4
Enter the number of the port to add to your Route: (-1 to end)
-1
Done Building a New Route named Baltimore to Brunswick
What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit
2
Which route would you like to use?
1. Baltimore to Brunswick
1
Baltimore to Brunswick
1. Baltimore, Maryland (N39.209 W76.517)
2. Boston, Massachusetts (N42.351 W71.052)
3. Bridgeport, Connecticut (N41.172 W73.179)
4. Brunswick, Georgia (N31.159 W81.5)
The total miles of this route is 1327.62 miles
What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit

Here is the rest of that run where we remove a port from a route and then we reverse the route.

What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit
3
Which route would you like to use?
1. Baltimore to Brunswick
1
Baltimore to Brunswick
1. Baltimore, Maryland (N39.209 W76.517)
2. Boston, Massachusetts (N42.351 W71.052)
3. Bridgeport, Connecticut (N41.172 W73.179)
4. Brunswick, Georgia (N31.159 W81.5)
Which port would you like to remove?
2
Baltimore to Brunswick
1. Baltimore, Maryland (N39.209 W76.517)
2. Bridgeport, Connecticut (N41.172 W73.179)
3. Brunswick, Georgia (N31.159 W81.5)
Route named Baltimore to Brunswick updated
What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit
2
Which route would you like to use?
1. Baltimore to Brunswick
1
Baltimore to Brunswick
1. Baltimore, Maryland (N39.209 W76.517)
2. Bridgeport, Connecticut (N41.172 W73.179)
3. Brunswick, Georgia (N31.159 W81.5)
The total miles of this route is 1054.49 miles
What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit
4
Which route would you like to use?
1. Baltimore to Brunswick
1
Done reversing Route 0
What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit
2
Which route would you like to use?
1. Brunswick to Baltimore
1
Brunswick to Baltimore
1. Brunswick, Georgia (N31.159 W81.5)
2. Bridgeport, Connecticut (N41.172 W73.179)
3. Baltimore, Maryland (N39.209 W76.517)
The total miles of this route is 1054.49 miles
What would you like to do?:
1. Create New Route
2. Display Route
3. Remove Port From Route
4. Reverse Route
5. Exit
5
Routes removed from memory
Deleting Ports
Deleting Routes

6. Compiling and Running

Because we are using a significant amount of dynamic memory for this project, you are required to manage any memory leaks that might be created. For a linked list, this is most commonly related to the dynamically allocated nodes. Remember, in general, for each item that is dynamically created, it should be deleted using a destructor.

One way to test to make sure that you have successfully removed any of the memory leaks is to use the valgrind command.

Since this project makes extensive use of dynamic memory, it is important that you test your program for memory leaks using valgrind:

valgrind ./proj3 proj3_data.txt

Note: If you accidently use valgrind make run, you may end up with some memory that is still reachable. Do not test this - test using the command above where you include the input file. The makefile should include make val (which is ok).

If you have no memory leaks, you should see output like the following:

==5606==
==5606== HEAP SUMMARY:
==5606== in use at exit: 0 bytes in 0 blocks
==5606== total heap usage: 87 allocs, 87 frees, 10,684 bytes allocated
==5606==
==5606== All heap blocks were freed -- no leaks are possible
==5606==
==5606== For counts of detected and suppressed errors, rerun with: -v
==5606== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)

The important part is "in use at exit: 0 bytes 0 blocks," which tells me all the dynamic memory was deleted before the program exited. If you see anything other than "0 bytes 0 blocks" there is probably an error in one of your destructors. We will evaluate this as part of the grading for this project.

Additional information on valgrind can be found here: http://valgrind.org/docs/manual/quick-start.html

Starter Codes

makefile

CXX = g++
CXXFLAGS = -Wall -g
IODIR = ../../proj3_IO/
proj3: Route.o Port.o Navigator.o proj3.cpp
$(CXX) $(CXXFLAGS) Route.o Port.o Navigator.o proj3.cpp -o proj3

Navigator.o: Port.o Route.o Navigator.h Navigator.cpp
$(CXX) $(CXXFLAGS) -c Navigator.cpp

Route.o: Port.o Route.h Route.cpp
$(CXX) $(CXXFLAGS) -c Route.cpp

Port.o: Port.h Port.cpp
$(CXX) $(CXXFLAGS) -c Port.cpp

clean:
rm *.o*
rm *~

run:
./proj3 proj3_data.txt

run1:
./proj3 proj3_data.txt

val1:
valgrind ./proj3 proj3_data.txt

submit:
cp Port.h Port.cpp Route.h Route.cpp Navigator.h Navigator.cpp proj3.cpp ~/cs202proj/proj3

ta1:
valgrind ./proj3 proj3_ta1.txt

Navigator.h

#ifndef NAVIGATOR_H
#define NAVIGATOR_H

#include "Port.h"
#include "Route.h"

#include < fstream >
#include < string >
#include < iostream >
#include < cstdlib >
#include < vector >
using namespace std;

//Constants used for calculating distance
#define PI 3.14159265358979323846
#define EARTH_RADIUS 3958.8 //in miles
#define DEG_2_RAD PI / 180
#define RAD_2_DEG 180 / PI

class Navigator {
public:
// Name: Navigator (string) - Overloaded Constructor
// Desc: Creates a navigator object to manage routes
// Preconditions: Provided with a filename of ports to load
// Postconditions: m_filename is populated with fileName
Navigator(string fileName);
// Name: Navigator (destructor)
// Desc: Deallocates all dynamic aspects of a Navigator
// Preconditions: There is an existing Navigator
// Postconditions: All ports and routes are cleared
~Navigator();
// Name: Start
// Desc: Loads the file and calls the main menu
// Preconditions: m_fileName is populated
// Postconditions: All ports are loaded and the main menu runs
void Start();
// Name: DisplayPorts
// Desc: Displays each port in m_ports
// Preconditions: At least one port is in m_ports
// Postconditions: Displays all ports. Uses overloaded < < provided in Port.h
void DisplayPorts();
// Name: ReadFile
// Desc: Reads in a file that has data about each port including name, location, degrees
// north and degrees west. Dynamically allocates ports and stores them in m_ports
// The vector can hold many ports.
// Preconditions: Valid file name of ports
// Postconditions: Dynamically allocates each port and enters it into m_ports
void ReadFile();
// Name: InsertNewRoute
// Desc: Dynamically allocates a new route with the user selecting each port in the route.
// Route named based on the first and last port automatically
// For example, Baltimore to Boston
// Once route is created, inserted into m_routes.
// Preconditions: Populated m_routes
// Postconditions: Inserts a new route into m_routes
void InsertNewRoute();
// Name: MainMenu
// Desc: Displays the main menu and manages exiting
// Preconditions: Populated m_ports
// Postconditions: Exits when someone chooses 5
void MainMenu();
// Name: ChooseRoute
// Desc: Allows user to choose a specific route to work with by displaying numbered list
// Preconditions: Populated m_routes
// Postconditions: Returns the index of the selected route minus 1
int ChooseRoute();
// Name: DisplayRoute
// Desc: Using ChooseRoute, displays a numbered list of all routes.
// If no routes, indicates that there are no routes to display
// User selects a route from list to display
// Displays numbered list of each port in route
// Displays total miles of a route using RouteDistance
// Preconditions: Routes has more than one port
// Postconditions: Displays all ports in a route and the total miles of the route
void DisplayRoute();
// Name: RemovePortFromRoute()
// Desc: Using ChooseRoute, displays a numbered list of all routes.
// User selects one of the routes to remove a port from.
// Displays a numbered list of all ports in selected route.
// User selects port to remove from list.
// Removes port from route. If first or last port removed, updates name of route.
// Preconditions: Routes has more than one port
// Postconditions: Displays updated route with removed port and new name
void RemovePortFromRoute();
// Name: RouteDistance
// Desc: Calculates the total distance of a route
// Goes from port 1 to port 2 then port 2 to port 3 and repeats for
// length of route. Calculates the distance using CalcDistance (provided)
// Aggregates the total and returns the total in miles
// Preconditions: Populated route with more than one port
// Postconditions: Returns the total miles between all ports in a route
double RouteDistance(Route*);
// Name: ReverseRoute
// Desc: Using ChooseRoute, users chooses route and the route is reversed
// If no routes in m_routes, indicates no routes available to reverse
// Renames route based on new starting port and ending port
// For example, Baltimore to Boston becomes Boston to Baltimore
// Preconditions: Populated m_routes
// Postconditions: Reverses a specific route by reversing the ports in place
// Must move ports, cannot just change data in ports.
void ReverseRoute();
// Name: CalcDistance (provided - DO NOT EDIT)
// Desc: Calculates the distance between two ports by using their coordinates
// Takes in port1 latitude (North), Port1 Longitude (West)
// Takes in port2 latitude (North), Port2 longitude (West)
// Preconditions: Requires two ports with their N (in degrees) and W (in degrees)
// Postconditions: Returns distance in miles between two ports
double CalcDistance(double port1_north, double port1_west,
double port2_north, double port2_west) {
double lat_new = port2_north * DEG_2_RAD;
double lat_old = port1_north * DEG_2_RAD;
double lat_diff = (port1_north-port2_north) * DEG_2_RAD;
double lng_diff = (port1_west-port2_west) * DEG_2_RAD;

double a = sin(lat_diff/2) * sin(lat_diff/2) +
cos(lat_new) * cos(lat_old) *
sin(lng_diff/2) * sin(lng_diff/2);
double c = 2 * atan2(sqrt(a), sqrt(1-a));

return double(EARTH_RADIUS) * c;
}
private:
vector< Port* > m_ports; //Vector of all ports
vector< Route* > m_routes; //Vector of all routes
string m_fileName; //File to read in
};

#endif

Port.h

#ifndef PORT_H
#define PORT_H

#include < string >
#include < iostream >
#include < iomanip >
#include < cmath >
using namespace std;

class Port {
public:
// Name: Port() - Default Constructor
// Desc: Used to build a new empty port
// Preconditions: None
// Postconditions: Creates a new Port for use in a Route
Port();
// Name: Port(string, string, double, double) - Overloaded Constructor
// Desc: Used to build a new Port passing it a name, location, north, and west
// Preconditions: None
// Postconditions: Creates a new port for use in a Route
Port(string, string, double, double);
// Name: ~Port() - Destructor
// Desc: Used to destruct a port
//**This function should be empty but must be implemented
// Preconditions: There is an existing port
// Postconditions: Port is deallocated and has no memory leaks!
~Port();
// Name: GetName()
// Desc: Returns the name of the port
// Preconditions: None
// Postconditions: Returns the name of the port
string GetName();
// Name: GetNext()
// Desc: Returns the pointer to the next port
// Preconditions: None (may return either port or nullptr)
// Postconditions: Returns m_next;
Port* GetNext();
// Name: GetNorth()
// Desc: Returns the northern coordinates of the port
// Preconditions: None
// Postconditions: Returns the N coordinates of the port
double GetNorth();
// Name: GetWest()
// Desc: Returns the western coordinates of the port
// Preconditions: None
// Postconditions: Returns the W coordinates of the port
double GetWest();
// Name: GetLocation()
// Desc: Returns the description of where the port is located
// Preconditions: None
// Postconditions: Returns the description of where the port is located
string GetLocation();
// Name: SetNext()
// Desc: Updates the pointer to a new target (either a port or nullptr)
// Preconditions: None
// Postconditions: Sets the next port
void SetNext(Port*);
// Name: operator< <
// Desc: Overloaded < < operator to return ostream from an Port
// Must not have a cout statement in this
// Preconditions: Requires an Port
// Postconditions: Returns ostream populated with Port's name and location
// **PROVIDED** Do not edit
friend ostream &operator< < (ostream &output, Port &myPort){
output < < myPort.m_name < < ", " < < myPort.m_location;
return output;
}
private:
string m_name; //Name of Port
string m_location; //Location of Port
double m_north; //North of port
double m_west; //West of port
Port *m_next; //Port pointer to next port
};

#endif

proj3.cpp

#include "Navigator.h"
#include < iostream >
using namespace std;

int main (int argc, char* argv[]) {
if (argc < 2)
{
cout << "You are missing a data file." << endl;
cout << "Expected usage ./proj3 proj3_data.txt" << endl;
cout << "File 1 should be a file with ports" << endl;
}
else
{
cout << endl << "***Navigator***" << endl << endl;
Navigator S = Navigator(argv[1]);
S.Start();
}
return 0;
}

Route.h

//Name: Route.h
//Project: CMSC 202 Project 3, Spring 2022
//Author: Jeremy Dixon
//Date: 2/22/2022
//Desc: This file contains the header details for the Route class
// A route is a linked list that uses ports as nodes

#ifndef ROUTE_H
#define ROUTE_H

#include < string >
#include < iostream >
#include < iomanip >
#include < cmath >

#include "Port.h"
using namespace std;

class Route {
public:
// Name: Route() - Default Constructor
// Desc: Used to build a new Route (linked list) make up of ports
// Preconditions: None
// Postconditions: Creates a new Route where m_head and m_tail point to nullptr and size = 0
Route();
// Name: SetName(string)
// Desc: Sets the name of the route (usually first port to last port)
// Preconditions: None
// Postconditions: Sets name of route
void SetName(string name);
// Name: ~Route() - Destructor
// Desc: Used to destruct a strand of Route
// Preconditions: There is an existing Route strand with at least one port
// Postconditions: Route is deallocated (including all dynamically allocated ports)
// to have no memory leaks!
~Route();
// Name: InsertEnd (string, string, double double)
// Desc: Creates a new port using the data passed to it.
// Inserts the new port at the end of the route
// Preconditions: Takes in a Port
// Requires a Route
// Postconditions: Adds the new port to the end of a route
void InsertEnd(string, string, double, double);
// Name: RemovePort(int index)
// Desc: Removes a port from the route at the index provided
// Hint: Special cases (first port, last port, middle port)
// Preconditions: Index must be less than the size of the route
// Cannot make route less than two ports. If the route has
// two or fewer ports, fails.
// Postconditions: Name may be updated. Size is reduced. Route has one less port.
void RemovePort(int port);
// Name: GetName()
// Desc: Returns the name of the route (Usually starting port to last port)
// For example: Baltimore to Brunswick
// Preconditions: Requires a Route
// Postconditions: Returns m_name;
string GetName();
// Name: UpdateName()
// Desc: Updates m_name based on the name of the first port in the route
// and the last port in the route
// For example: Baltimore to Brunswick
// Preconditions: Requires a Route with at least two ports
// Postconditions: Returns m_name;
string UpdateName();
// Name: GetSize()
// Desc: Returns the number of ports in a route
// Preconditions: Requires a Route
// Postconditions: Returns m_size;
int GetSize();
// Name: ReverseRoute
// Desc: Reverses a route
// Preconditions: Reverses the Route
// Postconditions: Route is reversed in place; nothing returned
void ReverseRoute();
// Name: GetData (int)
// Desc: Returns a port at a specific index
// Preconditions: Requires a Route
// Postconditions: Returns the port from specific item
Port* GetData(int index);
// Name: DisplayRoute
// Desc: Displays all of the ports in a route
// Preconditions: Requires a Route
// Postconditions: Displays all of the ports in a route
// Formatted: Baltimore, Maryland (N39.209 W76.517)
void DisplayRoute();
private:
string m_name; //Name of the Route
Port *m_head; //Front of the Route (Starting Point)
Port *m_tail; //End of the Route (Ending Point)
int m_size; //Total size of the Route
};

#endif

proj3_data.txt

Baltimore,Maryland,39.209,76.517
Boston,Massachusetts,42.351,71.052
Bridgeport,Connecticut,41.172,73.179
Brunswick,Georgia,31.159,81.5
Camden,New Jersey,39.943,75.104
Charleston,South Carolina,32.789,79.922
Charlottetown,Prince Edward Island,46.24,63.14
Corner Brook,Newfoundland and Labrador,48.967,57.95
Fall River,Massachusetts,41.722,71.159
Georgetown,South Carolina,33.367,79.29
Halifax,Nova Scotia,44.65,63.567
Happy Valley-Goose Bay,Newfoundland and Labrador,53.302,60.417
Jacksonville,Florida,30.321,81.665
Key West,Florida,24.559,81.784
Miami,Florida,25.784,80.183
Morehead City,North Carolina,34.717,76.724
New Bedford,Massachusetts,41.652,70.934
New Haven,Connecticut,41.299,72.905
New London,Connecticut,41.35,72.106
Philadelphia,Pennsylvania,39.919,75.202
Port Canaveral,Florida,28.414,80.608
Port Everglades,Florida,26.093,80.118
Port of Albany,New York,42.628,73.757
Port of New Hampshire,New Hampshire,43.074,70.738
Port of New York and New Jersey,New York and New Jersey,40.674,74.038
Port of Virginia,Virginia,36.947,76.33
Portland,Maine,43.65,70.251
Providence,Rhode Island,41.812,71.398
Richmond,Virginia,37.457,77.419
Saint John,New Brunswick,45.307,65.978
Savannah,Georgia,32.085,81.095
Searsport,Maine,44.453,68.925
St. Johns,Newfoundland and Labrador,47.617,52.75
Sydney,Nova Scotia,46.138,60.183
Wilmington - Delaware,Delaware,39.716,75.507
Wilmington - North Carolina,North Carolina,34.239,77.954
Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.