Skip to content

Daniel-Jarka/Metro-Simulator

Repository files navigation

/******************************************************************************

  • Project 1: Metro Simulator
  • README
  • Author: Daniel Jarka djarka01 ******************************************************************************/

B. Program Purpose:

 This program is designed to simulate a simple representation
 of a train picking up and dropping off passengers at different
 train stations. This program particularly demonstrates how a queue 
 is a useful implementation of a list to represent a "first come, 
 first serve" order of adding and removing elements from a list.
 Additionally, the client has access too much fewer member functions
 of the MetroSim class, since the purpose of this program for a client
 is akin to a game. A client will run the program and their only
 options for manipulating the program are by running the specific
 commands that change the state of the simulation. To that end,
 the client can move the train, add passengers to any station,
 and terminate the program. For each command run by the client,
 the program will print an updated representation of the simulation
 to std::out. Additionally, the program prints the information
 of each departing passenger to an output file. Finally,
 the program can accept an optional commands file parameter
 that reads input directly from a file instead of a user. 

C. Acknowledgements:

 I consulted https://cplusplus.com/reference/vector/vector/
 and https://cplusplus.com/reference/list/list/ to learn how
 to implement and use std::vector and std:list. 

 I used https://cplusplus.com/reference/string/string/
 to look for some useful functions for strings (I used empty()).

 I looked at https://cplusplus.com/reference/ostream/ostream/
 to learn more about ostreams.

D. Files:

 Passenger.cpp:
      Implementation of Passenger class. Used to represent
      each individual passenger at the stations or on the train
      in MetroSim.

 Passenger.h:
      Interface of Passenger class.

 PassengerQueue.cpp:
      Implementation of PassengerQueue class. Used to represent
      the line of passengers waiting to board/depart the train
      in a queue style format.

 PassengerQueue.h:
      Interface of PassengerQueue.

 unit_test.h:
      A unit testing file for the Passenger and PassengerQueue Classes.
      Runs in conjunction with the unit_test framework 
      to allow for testing of individual functions.

 Makefile:
      File used to run the "make" command which compiles and builds
      the program.
 
 MetroSim.cpp:
      Implementation of MetroSim class. Used to build the front-end
      interface and link it to the back-end functions to create 
      a proper metro simulation. 
 
 MetroSim.h:
      Interface of MetroSim class.

 main.cpp:
      Driver file which interacts with the user, the PassengerQueue class
      and the Passenger class.
 
 stations.txt:
      Test input data.

 test_stations1.txt:
      Test input data. Run with test_commands1.txt only.

 test_stations2.txt:
      Test input data. Run with test_commands1.txt only.

 test_commands.txt:
      Test input data.

 test_commands1.txt:
      Test input data.

 test_commands2.txt:
      Test input data.

 README: 
      This file.

E. Compile/run: - Compile using make MetroSim - run executable with ./MetroSim stationsFile passFile [commands]

F. Architechtural Overview:

 The backbone of this implementation relies on the Passenger and 
 PassengerQueue classes. The PassengerQueue is a queue that stores
 Passengers in a std::vector which allows the program to pop elements
 from the front and add elements to the back of the queue. The MetroSim
 class then uses two different std::vectors that contain PassengerQueues.

 The "train" in this implementation is a vector of PassengerQueues.
 Since passengers are ordered by their departing station, my train
 is initialized to have the same number of "cars" or queues as there
 are stations. When a passenger is added to the train from a station,
 the program uses the passenger's departing station to sort the
 passenger into the correct "car" or queue. For example,
 a passenger with a departing station "3" will be added to the
 third car of the train, which represents a queue of all passengers
 that have a departing station "3." Since each car is a queue,
 passengers are added and removed in order of their arrival. 

 Each "station" is implemented a little differently. First, the program 
 uses a struct to store station names and station numbers, as well as a
 PassengerQueue. This struct refers to one instance of a station, so each
 struct is then added to a vector of station structs. In this way, the
 program can keep track of the name and number of each station, as well
 as the passengers that are queued at each station. Unlike the train
 vector, passengers are added to a station queue based on their arriving
 station. For example, if a passenger is added to the simulation with
 arriving station "5," then this passenger is added to the queue that
 represents station number 5 in the stations vector. 

G. Data Structures:

 The ADT here is a list, which is an ordered sequence of elements.
 There are two primary implementations of the list to run the program. 

 The main data structure is a queue, while the secondary data structure
 is a vector/array list. The primary role of the vector in this 
 implementation is to store different queues. The vector is useful because
 it allows for quick access to each queue. Since it is unreasonable for 
 a client to initialize an instance of MetroSim with billions of stations,
 the storage concern of using a vector/array list is practically 
 non-existent here. Of course, a client CAN initialize an instance of 
 MetroSim with billions of stations and potentially cause the computer 
 to run out of memory, but let'sassume this will not happen. 
 
 The queue is the main focus of this implementation because it is a useful 
 data structure to represent the removal/addition of elements in a 
 "first come, first serve" basis. Since passenger instances are waiting in
 a "line" to either board or depart the train, a queue is used for 
 elements that can only be added at the back and removed from the front. 
 Of course, there are other situations in which a queue data structure is 
 very useful. For example, a fast food restaurant with a mobile order
 feature will use a queue to show which order should be completed first.
 Any newly placed orders will be added to the back of the queue, since
 they are of least priority. Another example of a queue is when you
 want to purchase tickets for a concert on ticketmaster. Since there
 are a limited number of tickets, you are placed on a queue in order
 of who opened the web page first. You wait on the queue while the
 people in front of you purchase their tickets before you have your turn.
 (All of the tickets will probably be gone by then).

 Though queues are more "restricted" linked lists, this actually makes them
 very useful. Since there are very few operations you can perform to
 a queue, namely adding to the front and removing from the back,
 these operations are very fast. Because a queue is essentially a 
 linked list, memory is of relatively little concern as well. In this
 implementation, however, each queue is stored in a vector. While
 the queues themselves may not take up a lot of relative space for a large
 number of elements, the vectors can require a relatively larger amount
 of space for a very large number of queues to store. 

 While being a restricted linked list is an advantage, it can also be
 a disadvantage for a program that requires direct access to any
 element in the list. Queues should only be used for programs that
 need to represent a queue-like structure, otherwise they are difficult
 to work with. Be sure to stay away from queues if you need to operate
 on a list with anything other than popping from the front and adding to
 the back. 


The ADT of this program is a list, which is an ordered sequence of elements.
The main data structure of this homework is a Linked List, which 
is a structure where each element points to another element in the list
in an ordered sequence. This specific implementation is a doubly linked
list, so each element actually points to the next and previous elements
in the list. The advantage of using a Linked List is that the
user does not have to worry about memory for very large lists as much
as they would in an array list. This can be seen with any insertion 
function,like insertAt() or pushAtBack(). Since data in this structure is 
stored by pointers, the program only needs to find the correct location 
in the list. At this point, it can create a new node without much trouble 
or memory. This is unlike an array list, since the size of an array must 
always be declared. This creates issues when a very large list is required,
since our previous implementation of array lists doubled their capacity 
whenever more space was needed. A disadvantage, however, is that adding 
elements between the front and end of the list is not fast as it would be 
in an array list. For example pushAtBack() takes time to find the last 
position in the list because the elements stored in the list are not 
contained within specifically known memory locations in the computer. 
To find the last element, the program must traverse the list through n 
elements to find the last element. So the big O complexity is O(n),
which isn't actually as crazy as some other algorithms (not specifically
in this implementation) can get!

Algorithmically, there aren't any particularly complicated functions
for queues. There really is just enqueue() and dequeue(), both of 
which are O(1), since the program will always know where the front
and back of the queue are. In MetroSim, however, mm() is O(n).
Although the primary operation is still enqueue(), this operation
can be called n times, since it depends on how many passengers are
at a station. In any case, the O complexity of this program is 
quite fast!

H. Testing:

 I used the unit_test framework to test the Passenger and PassengerQueue
 classes. I tested every function, particularly the functions
 I wrote for PassengerQueue, to make sure I'm in good shape for the
 rest of my MetroSim implementation.

 Testing MetroSim was a little more difficult, since I could not as
 easily use the unit_test framework. Instead, I used the_MetroSim
 as a reference and incrementally ran my own implementation with
 each function I completed. First I tested to see that my initial
 state of the program matched. Then I made sure that my "train"
 was printing correctly. Next, I made sure passengers were added 
 and printed correctly. I did this until I completed an implementation
 I felt confident in. At this point, I used the provided testing files
 to diff test my MetroSim with the_MetroSim. After passing this test,
 I created my own station and command files to try to go over as many
 different cases as possible. For example, using only two stations, 
 passing a file that does not exist, and ending the program before
 removing all passengers. 

I. Time Spent:

 I spent about 8-9 hours on this assignment.

About

Contains a Metro Simulator

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors