[Please note that the direction of motion also is a critical part of a route's definition---it must be possible for some buses to move clockwise while others move counter-clockwise.]
At the demo, we will ask you to make specific changes to one or more of the following aspects of your simulation:
Please note that simply randomizing these items is not sufficient; we will be
asking for specific changes. For example, the grader might point to a
tile and say ``at t = 0
, there must be a TCAT bus here.''
When you render the street map, please be sure to demarcate the street-segment tiles, so that the graders can easily see the boundaries of each tile. [It would suffice to simply draw a (clearly visible) border around each tile.]
Agents are expected to follow the traffic rules voluntarily---you are not required to implement a ``monitor'' that prevents agents from making illegal moves.
Your directed graph data structure does not need to provide methods that delete vertices and edges. Edge weights are likewise not required. Also, if you choose to use Weiss's graph-related classes, you need not include fields (e.g., Vertex.prev and Vertex.scratch) that pertain only to certain graph algorithms.
You may assume that the directed graph is time-invariant, i.e., you may assume that the map will not change after it's initialized.
Don't worry about producing a highly polished, professional-looking gui. We will be evaluating functionality, not aesthetics.
Model / view separation is strongly recommended but not mandatory.
class StreetSegment { public final static int TILES_PER_LANE = 5; // ... }...and then, everywhere else in your code, use that variable instead of the actual numeric value (e.g., use StreetSegment.TILES_PER_LANE instead of the numeric literal 5).
Why is this a good idea? Suppose that you instead simply used the numeric literal 5 everywhere...
// in one of the gui-related classes... for (int i = 0; i < 5; i ++) { // ...render tile i in the eastbound lane... } // elsewhere, in one of the initialization-related classes... for (int i = 0; i < 5; i ++) { // ...create tile i in the eastbound lane... } // elsewhere, in an optional extension / add-on class... for (int i = 0; i < 5; i ++) { // ...increment the congestion counter if // tile i in the eastbound lane is occupied... }The "magic number" 5 would thus be sprinkled throughout a large number of your source files. Now, let's consider what would happen if you subsequently decided to change the number of tiles per street-segment lane from 5 to 6... Ouch! You'd have to comb through all of those files, changing 5's into 6's. (And, even worse, what if you overlooked one of the 5's---or mistakenly "damaged" a 5 that didn't have anything to do with street segments?)
With a symbolic constant, on the other hand, life would be much easier. It would simply be a matter of making a rather obvious change to a single line...
public final static int TILES_PER_LANE = 6;...in the body of the StreetSegment class.
Aside: in the tiles per street-segment lane case, it would be even better to arrange things so that the number of tiles per lane on a given street segment could be set when the segment is constructed / initialized, e.g.,
class StreetSegment { public final static int DEFAULT_TILES_PER_LANE = 5; protected final int tilesPerLane; public StreetSegment(int tilesPerLane) { this.tilesPerLane = tilesPerLane; } public StreetSegment() // use the default... { this(DEFAULT_TILES_PER_LANE); } }...elsewhere in the code, you'd refer to the final instance variable tilesPerLane (either directly or via a "getter" method) instead of the final class variable. This approach would make it much easier to later allow street segments to be of different lengths, rather than all street segments referring to the same default length.