In this assignment, you will be honing your skills for
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
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)
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:
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.
Your are being provided with
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
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.
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,
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.
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.
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.
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).
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:
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
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.
There are three more classes that you are to define to implement different loaders They are
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.
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)
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)
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.
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.