In this assignment, you will be honing your skills for

  • 1. Working with java interfaces
  • 2. Working with arrays one and two-dimensional
  • 3. Using public methods in classes for communication
  • 4. Further developing testing skills
  • 5. Writing your own javadoc

This is a longer assignment than either #1 or #2, You should start early.

An english description overview of objects and how things work.

There are four kinds of objects in this assignment

  • 1. TrainCar. These are cars of a cargo-carrying train. Each car has maximum weight to hold cargo.
  • 2. Trains. Trains have multiple cars. Cars may have identical cargo capacity or differing cargo capacities
  • 3. Items. These are various kinds of goods that we want to be able to load onto a cargo train. An item could be any object that support a specific and formal java interface.
  • 4. Loader - A person (actually algorithm) that decides if an an item can be loaded onto a train. Different Loaders use different algorithms. For example, one might load from the front to the back, another might load from back to front. You will be implementing four different loading algorithms.

In addition to these four kinds of objects, we are supplying you with a java program that allows you to write tests to see how your program, similar to assignment #2. We want you to focus mostly on four objects above.

So how do things fit together (Again, in English, more programmatic details follow in this assignment)

  • a Train is created with a specific Loader algorithm
  • Train Cars are added to the train to give it cargo capacity
  • Items are loaded onto the train

Some things to note: When a particular train is created, the loader algorithm never changes for that Train. There might be multiple trains, each with their own loader. Train cars can be added at anytime to a Train. Items can be loaded at any time. This means that I might create a Train, add some cars, load some items, add some more cars and load some more items. Cars are never removed from a train. Items are never removed. Cars are numbered starting at 0. The first car added is Car 0, then next car is Car 1, etc.

Once a Train has been loaded I might request the following of the Train:

  • What is the total weight of Cargo in the train
  • What is the total weight of Cargo of a particular car in the train
  • Give me a 2D array of all the items in the train. The row index is the car#, the columns of that row reference the Items in the order in which they were loaded
  • GIve me a 1D array of all the items of a single car in the train
  • Tell how many item of a particular type are loaded in the car, or train.

IMPORTANT NOTE

Not all of the code distributed to you will initially compile. Specifically TrainMain and Train will NOT compile because TrainCar does not exist. Your first task is to implement TrainCar.

TASK 1 : Read The definition of the Item interface and implement TrainCar

Your are being provided with

  • 1. Item.java
  • 2. Automobile.java
  • 3. Ford.java
  • 4. javadoc of TrainCar.java

You will not need to change or turn in Item, Automobile, or Ford. You cannot redefine Item.java. It is a formal interface definition and that is the interface for which we will test your homework. Automobile and Ford are classes that implement the Item interface. You should be able to answer the following questions about this code

  • given these definitions, is the statement new Automobile() allowed in any java file?
  • Does Ford.java implement the Item interface? That is, is the statement Item it = new Ford(mustang); legal?
  • How is the constructor of Automobile invoked in Ford.java?
  • Why do you think that the method model2weight in Ford.java needs be declared as a class method?

Implementing TrainCar

TrainCar implements some straightforward methods. Its job is to store references to objects of type Item. Since Item is an interface, this means store objects that implement the Item interface.

  • A TrainCar has a maximum weight.
  • It has a method, canLoad() that returns a boolean to say if an item can be loaded
  • Is has a method, load(), that adds an item to the contents of the TrainCar. load() should check the result of canLoad() before loading.
  • Items are stored sequentially (in an internal array or ArrayList). The first item loaded is index 0, second is index 1, etc.
  • getContents() returns an array of Items that have been successfully loaded. It returns in the order in which they were loaded.
  • getWeight() returns the sum of the weights of all the Items it contains
  • See the TrainCar.pdf for the javadoc generated from our implementation.

You are being provided javadoc for TrainCar, but no starter code. We expect your version of TrainCar to reasonably reproduce the javadoc, that means that you have to write your own javadoc comments in your version of TrainCar.java. We are not concerned about character-by-character reproduction of your javadoc comments when compared to the supplied javadoc webpage. However,

  • 1. All methods and constructors must be documented in the javadoc style
  • 2. % javadoc TrainCar.java should produce no errors or warnings about missing documentation.

Other requirements of TrainCar:

  • 1. Implement all of the public methods
  • 2. Define no other public methods, constructors, or fields
  • 3. You may use ArrayList or the Arrays class internally to your implementation, but that is not required. The assignment is easily done with standard arrays.
  • 4. you may add any number of private variables or methods
  • 5. To compile TrainCar, only Item.class should need to already be compiled.

A strategy for developing and testing TrainCar

You should create a small program that creates a TrainCar instance, some instances of Ford and then loads the TrainCar with your Automobile (Ford) instances. Finally it should print out the item descriptions. We are not grading this and you are not handing in the small program. Its up to you to figure out what you want to test to verify that your TrainCar methods are working properly. You shouldnt skip this step, or other parts of the assignment will take longer. Your small program will allow you to become familiar with the Item interface. Dont forget to test edge conditions, like trying to load more into already full car, or trying to load into a car with no cargo capacity.

In order to get started with the file TrainCar.java, you should make sure to write a working stub for each method in the javadoc. That is, write a method that returns some (probably incorrect) value that matches the return type, like -1 for an int, or null for an array. This will make sure you have a class definition that can compile with the other pieces of the project sooner rather than later.

Task 2 - Create an Electronics class that Implements Item

You are to create an Electronics class that implements Item. The constructor should have the following signature:

public Electronics (String description, double weight)

You should override the toString() method of Object so that the string returned has the following format:

Electronics: < description> (< weight> KG)

Where < description> and < weight> are the String description passed in the constructor and < weight> is the weight passed into the constructor. Example toString Output:

Electronics: SystemZ-Desktop (6.2 KG)

would the String return with the following statement

new Electronics(SystemZ-Desktop, 6.2).toString()

There are no other requirements of the Electronics class.

Suggested testing of Electronics

modify your small test program above and add the creation of some number of Electronics objects and add them to the TrainCar instance. (TrainCar itself should need NO modification to accommodate Electronics, why?) You should only need to modify a few lines of code of your test program to construct a TrainCar instance that now has Fords and Electronics packed.

You will turn in Electronics.java.

It should be documented with javadoc, implement the Item interface, and provide the appropriate constructor and toString() method. There are no other requirements of Electronics. java (the class be will short, 15-20 lines total).

Task 3: Train.java and TrainMain.java

We are providing you with a starter Train.java. It has been documented using javadoc comments and you should look at these and (if it helps you) generate the doc for reference. We are also providing FrontLoader.java and Loader.java. FrontLoader.java is simple Loader algorithm. You should develop Train.java in steps. Its important to reason about how the Loader is being used, how to add TrainCars to the Train instance, how to return the various Item [] and Item [][] arrays being asked for, computing total weight of the train, and the like.

TrainMain.java is testing program that requires Train, TrainCar, one or more classes the implement Loader, one or more classes that implement Item. It is pretty complete, but you need to read it. Like PR#2 you will turnin in some testing scenarios that use the commands defined in TrainMain.java. There are several lines marked FIXME in TrainMain.java -- these indicate places where, once you implement some other piece, you can remove the comments and enable some new functionality. For example, when you implement the Electronics class, you can then use the code in the electronics command to construct and load those items. The same goes for the different loaders.

TrainMain has several commands you can use; a few examples are in testinput1.txt:

  • manifest -- Prints out the number of cars, total train weight, and a summary for each car containing the number of items and total weight (using the methods you implement to get this information, so if you havent implemented one of the appropriate methods, the wrong information will print)
  • manifest n -- Prints out all the items in the car at index n
  • add-cars n w -- Adds n cars each with weight capacity w to the train
  • electronics desc w n -- Attempts to load n electronics items, each with weight w and description desc (you can enable this once you implement Electronics)
  • ford model n -- Attempts to load n Fords of the given model onto the train, each with the given model

When TrainMain starts up, it prompts the user which of the four loaders theyd like to use. One of the given loader type is instantiated, and the Train constructor is called with the given loader. Initially, only FrontLoader is available; you can enable the other three as you implement them (see below for more on loaders).

We suggest the following order of development

  • Put in default values for the return of each existing method
  • Implement/Debug the Train Constructor
  • Implement/Debug addCars (test by just adding a single car)
  • create and add some items to the Train (since it is a single car at stage is should behave just like adding items in Task 1).
  • Implement/Debug the getContents(int car) method
  • Implement/Debug the getWeight(int car) method
  • Add multiple cars to the train.
  • Create and add items to the Train. add enough items that the FrontLoader will have to eventually choose to load items into the second and third car.
  • Verify that getContents/getWeight work for all cars
  • Implement/Debug getWeight() - weight of all cargo
  • Implement/Debug getContents() - All contents, car by car.

Note that all of this testing is being done with just a single Loader algorithm, the FrontLoader. You should be able to manually verify the output.

Task 4: Develop three more Classes that implement Loader

There are three more classes that you are to define to implement different loaders They are

  • RearLoader.java
  • RoundRobinLoader.java
  • FairLoader.java

Since these are just strategies for which car to choose when loading, they each have different goals. Note that Train.java, TrainCar.java, Item.java, Ford.java, Automobile.java. Electronics.java do not have to change at all as you create new classes that implement Loader. In our setup only TrainMain.java needs to know how to create a specific Loader and then instantiate a Train with that loader. Please re-read this paragraph, understanding why this works (via runtime polymorphism) is key to gaining insight into a key feature of any object-oriented language.

The following gives rules/examples of how each Loader strategy fills a train. For this example:

Train has 5 cars, Cars have the following weight Capacities:
0: 10 KG
1: 8 KG
2: 6 KG
3: 4 KG
4: 3 KG

We will load Items A-Z, in that order. All items are 3KG in weight. The train has a maximum capacity of 31 KG.

RearLoader -- Loads from rear of the Train first

Loading A - Z (we cannot load all), the train will loaded as follows. This the output from a simple test program that loads electronics classes into a train with cargo capacities above

=== Train Weighs 27.000000 KG ===
==== CAR 0 (9.000000 KG) ====
Electronics: G (3.000000 KG)
Electronics: H (3.000000 KG)
Electronics: I (3.000000 KG)
==== CAR 1 (6.000000 KG) ====
Electronics: E (3.000000 KG)
Electronics: F (3.000000 KG)
==== CAR 2 (6.000000 KG) ====
Electronics: C (3.000000 KG)
Electronics: D (3.000000 KG)
==== CAR 3 (3.000000 KG) ====
Electronics: B (3.000000 KG)
==== CAR 4 (3.000000 KG) ====
Electronics: A (3.000000 KG)

RoundRobinLoader --

Starting from the front it loads the first item in car 0, next item in car 1, when it gets to car 4, the next car loaded is 0. If there is no capacity in the car that should be next, it keeps trying in round-robin fashion until it exhausts all possibilities. The RoundRobinLoader must remember the last car it selected for chooseCar. Below is output of one of our simple test programs that is loading electronics using the RoundRobinLoader

== Train Weighs 27.000000 KG ===
==== CAR 0 (9.000000 KG) ====
Electronics: A (3.000000 KG)
Electronics: F (3.000000 KG)
Electronics: I (3.000000 KG)
==== CAR 1 (6.000000 KG) ====
Electronics: B (3.000000 KG)
Electronics: G (3.000000 KG)
==== CAR 2 (6.000000 KG) ====
Electronics: C (3.000000 KG)
Electronics: H (3.000000 KG)
==== CAR 3 (3.000000 KG) ====
Electronics: D (3.000000 KG)
==== CAR 4 (3.000000 KG) ====
Electronics: E (3.000000 KG)

FairLoader -

Each time chooseCar is invoked, FairLoader starts at the front of the train (car 0) and finds the first least-loaded car in which the cargo will also fit. In the example A-Z and cars, FairLoader will give the identical results as RoundRobinLoader. However, that is not always True. Suppose we now load a sequence of items:

A, A1, B, B1, C, C1, D, D1, E, E1, F, F1,....

Where the 1 versions of the items are 1KG, but we have the same Car capacity as before. In our test program that generated the following output, it stopped adding items the first time it encountered an item that would not fit in any car.

RoundRobinLoader

=== Train Weighs 28.000000 KG ===
==== CAR 0 (8.000000 KG) ====
Electronics: A (3.000000 KG)
Electronics: C1 (1.000000 KG)
Electronics: E1 (1.000000 KG)
Electronics: G (3.000000 KG)
==== CAR 1 (8.000000 KG) ====
Electronics: A1 (1.000000 KG)
Electronics: D (3.000000 KG)
Electronics: F (3.000000 KG)
Electronics: G1 (1.000000 KG)
==== CAR 2 (5.000000 KG) ====
Electronics: B (3.000000 KG)
Electronics: D1 (1.000000 KG)
Electronics: F1 (1.000000 KG)
==== CAR 3 (4.000000 KG) ====
Electronics: B1 (1.000000 KG)
Electronics: E (3.000000 KG)
==== CAR 4 (3.000000 KG) ====
Electronics: C (3.000000 KG)

FairLoader

=== Train Weighs 31.000000 KG ===
==== CAR 0 (10.000000 KG) ====
Electronics: A (3.000000 KG)
Electronics: E (3.000000 KG)
Electronics: G1 (1.000000 KG)
Electronics: H (3.000000 KG)
==== CAR 1 (8.000000 KG) ====
Electronics: A1 (1.000000 KG)
Electronics: C1 (1.000000 KG)
Electronics: D1 (1.000000 KG)
Electronics: E1 (1.000000 KG)
Electronics: F1 (1.000000 KG)
Electronics: G (3.000000 KG)
==== CAR 2 (6.000000 KG) ====
Electronics: B (3.000000 KG)
Electronics: F (3.000000 KG)
==== CAR 3 (4.000000 KG) ====
Electronics: B1 (1.000000 KG)
Electronics: D (3.000000 KG)
==== CAR 4 (3.000000 KG) ====
Electronics: C (3.000000 KG)

The way to see this is simply run the FairLoader chooseCar algorithm. Well do this Step by Step, to indicate the load of each car. Hopefully, its clear why, Load A, Load A1, Load B, Load B1, Load C, ends up with car weights as follows: Yellow Cell indicates a fully loaded car, BOLD indicates which car was loaded

3 1 3 1 [3]

Now, attempt to Load C1, C1 weighs 1KG, car 1 and car 3 have the least weight. Our tie breaker says, take closest to the front, Hence C1 goes into Car 1

3 2 3 1 [3]

Load D (3KG). The car with the least weight is car 3, so load it there

3 2 3 [4] [3]

Load D1 (1KG) - car 1

3 3 3 [4] [3]

Load E (3KG) - Car 0

6 3 3 [4] [3]

Load E1 (1KG) - Car 1

6 4 3 [4] [3]

Load F - Car 2

6 4 [6] [4] [3]

Load F1 - Car 1

6 5 [6] [4] [3]

Load G - Car 1

6 [8] [6] [4] [3]

Load G1 - Car 0

7 [8] [6] [4] [3]

Load H - Car 0

[10] [8] [6] [4] [3]

Hint: Think about what you need to calculate each time FairLoader is trying to figure out which car should be loaded. One way to go about this is to create an array of current car weights. Then walk through the array of TrainCars passed to chooseCar and determine if the item could be loaded into the car, If so, record the current weight of the car (what method would you invoke on a TrainCar instance to determine current weight and ability to load? -- USE those methods). If it could not be loaded, record a nonsense weight. With that in hand, you can then walk the array of weights looking for the minimum weight that isnt nonsense. Record the index of that minimum weight, and you have found your car. Remember to take care of the case when the item fits in no car.

TASK 5 : Test Cases

Just as in PR2, you will use input and output files, along with TrainMain.java, to test your program. The script is slightly smarter this time, and will trim beginning and ending whitespace from both before comparing. Submit exactly 5 different test files (testinput1.txt through testinput5.txt) with corresponding expected outputs (testoutput1.txt through testoutput5.txt),

Note: Testing also helps you make sure that your program is correct, and is a huge aid in debugging. We recommend that you run python run_tests quite frequently when developing -- running it after each time you compile your program is not too often. Once you get a small number of tests passing, it becomes easy and fun to build on them and see how robust your implementation is, and you get the added benefit of being able to tell if anything breaks later when you go back to make other edits.

To emphasize: The goal of this part of the assignment is for you to practice writing code that helps you in debugging. A good test should have a known outcome that you can verify.

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.