CIT 591Traffic Jam Hints
Fall 2004, David Matuszek

Here are some of the questions that came up during lab. There are no new requirements on this page, just (hopefully) better explanations than some that I gave.

Referencing methods

If an object wants to reference a method of its own, all it needs to do is to name the method and supply any needed parameters.

For example, inside an object of type City, you can say:

printTrafficGrid();

Inside a Car object, you can say:

decideDestination();
if (isAtDestination()) {...}

If an object wants to talk to another object, it must name the object before it names the method and gives actual parameters. For example, inside an object of type Car, you can say:

city.removeCarFrom(row, column);
row = rand.nextInt(city.getNumberOfRows());
System.out.println("New car placed at " + row + ", " + column + ".");

If one object needs to give a reference to itself to another object, it uses the keyword this. The keyword this means "me." For example, in a Car object you might say:

city.placeCarAt(this, row, column);

which means, "City, place me at this row and this column."

Creating Cars

Remember that every class has a constructor. If you don't write one, Java supplies the default constructor, which takes no arguments and sets all its instance variables to zero (or false, or null). Since I didn't write a constructor for Car, you create a new car with new Car().

The main method (in City) creates a city, and the city creates cars. This may not seem to be the most logical place to create cars, but unless we make the program a great deal more complicated, it's the easiest place. There is only one city; there are only as many cars as you create by calling new Car().

Cars are created with all their instance variables set to zero. Although [0][0] is a legal location in the traffic grid, it isn't where you want all your cars to be. So after you (1) create each car, you have to (2) find a place in the city to put it, then you have to (3) choose a destination for it. There are methods (in the Car class) for choosing an initial location and for choosing a destination; there is a method (in the City class) for determining whether your initial location is vacant, or whether you have to choose a different initial location. No two cars can have the same initial location; however, it's fine if different cars have the same destination.

Placing cars

For each car you create, you put a reference to it in two places. You aren't duplicating the car when you do this; you simply have two ways to access the (same) car.

As you create each car, you should put a reference to it in the cars[] array. As you find a place to put each car, you should put a reference to it in the trafficGrid[][] array.

This is the cars array. You can use this to step through all of the cars, and do something with each (such as tell them to move).

It isn't as easy to use this array to determine if a particular location in the city is occupied.

The cars array is in the city object.

This is the trafficGrid array. You can use this array to determine quickly and easily if a particular location in the city is occupied, and if so, which car is there.

It isn't as easy to use this array to find all the cars.

The trafficGrid array is in the city object.

Each car has to know its own location, which it keeps in its row and column instance variables. When a car is looking for an initial location, it uses its placeNewCarInCity method to choose one randomly, then asks the city if that location is occupied (the city has an isOccupied method for this purpose). However, once the car has chosen a location for itself, the city also needs to know where it is, because it is the city's job to keep track of all cars, report collisions, and stop the program when cars are no longer moving. Hence, the car has to call city.placeCarAt to give the city this information.

Collisions

There are two ways a collision can occur. A newly created car can try to place itself in a city location that is already occupied; or an existing car can try to move into a city location that is already occupied. If you have written the program correctly, and your cars look where they are going (again, with isOccupied), collisions should not happen.

When you move a car, this information has to be kept in two places. The car has to keep track of its own row and column, and the city has to keep a reference to the car in the correct location in its trafficGrid. Hence, whenever a car changes location, it has to tell the city that it is no longer at the old location (removeCarFrom) but is now in the new location (placeCarAt).

Why, then, should the city also check for a collision? Because it is responsible for its own data. It cannot put two cars in the same location. It should not depend on the Car class to do things correctly. If it did, then an error in the Car class would cause the data in the city object to become incorrect. If this causes things to go wrong at some later time, it would appear that the error was in the City class (because it had, for example, ten cars in its cars array but only eight in its trafficGrid array). This would make the program much harder to debug.

It is an important principle that objects should protect their own data.

Printing

When you print the trafficJam array, you have to look at every array location individually (in nested loops), and decide what to print for that location. There are two cases:

When you go to print a location containing a car, you must ask the car how it wants to be printed. The car has a toString() method just for this purpose. So you might do something like:

System.out.print(city[i][j].toString());

(since city[i][j] refers to some car).

In addition, the toString() method has a "magical" property--I'll reveal later how the trick is done--that allows it to be called automatically when you try to print an object that has this method. You don't need to understand or use this fact yet, but if you want to try it out, what it means is that the above print statement can be abbreviated to just:

System.out.print(city[i][j]);

Comments

We have not yet discussed HTML, but HTML is the language that web pages are written in. For reasons we will go into later, if you want a "<" symbol to appear on a web page, you have to write it as &lt;, and if you want a ">" symbol, you have to write it as &gt;.

javadoc (which we also have not yet discussed) uses HTML, and comments written as /**...*/ are javadoc comments.

My comment for the Car's toString method looks like:

    /**
     * Returns a short string representing the status of this car.
     * Possible return values are:
     * <ul>
     *   <li>" D" : This car has reached its destination.</li>
     *   <li>" ^" : This car is trying to move north.</li>
     *   <li>" &gt;" : This car is trying to move east.</li>
     *   <li>" v" : This car is trying to move south.</li>
     *   <li>" &lt;" : This car is trying to move west.</li>
     *   <li>" ?" : I don't know what this car is doing (shouldn't happen).</li>
     * <ul>
     */
This is actually correct. When viewed as HTML, this comment will look like:<

Returns a short string representing the status of this car. Possible return values are:

To see this in BlueJ, choose Interface from the editor window, rather than Implementation.

Correcting my code

The code that I gave you is excerpted from a working program. You should not need to change anything (except certain return statements that are specially marked). In particular, I've made certain variables and methods private so that you cannot refer to them from an object of a different kind.

Leave my code as it is; just add to it, don't change it. If you run into any insurmountable problems, contact me and we'll figure out what to do about it.