26. Yet more building a simulation

Part of CS:2820 Object Oriented Software Development Notes, Spring 2021
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

 

Intersections

At the very outer level, in the abstract class Intersection, we need to add a commitment to a public Intersection.enter() method:

public abstract void enter( double t );

This commits every subclass of intersection to have such a method. Later, when we start dealing with stop lights, we'll find that this is an inadequate specification, but for now, we can add a dummy enter method to class StopLight that does nothing, and we can add a useful method to class NoStop:

/** a vehicle enters a no-stop intersection
 *  @param t, the time of entry
 *  this is typically called from the r.leave() for some road r
 */
public void enter( double t ) {
    this.waiting = this.waiting + 1;
    if (waiting <= 1) { // this is the only waiting car
        Simulator.schedule(
            time + travelTime,
            (double t)-> this.leave( t )
        );
    }
}

This looks very familiar. So familiar that we can rewrite the code we already wrote in class Source to simply call the enter method instead of duplicating the code:

private void produce( double time ) {
    super.enter( time );

    Simulator.schedule(
        time + rand.nextExponential( period ),
        (double t)-> this.produce( t )
    );
}

Of course, we must add Sink intersections to match our Source intersections, but a trivial Sink class will suffice. We need to

Testing

Once we have source intersections, roads and sinks, we have enough to test. Because we also have uncontrolled intersections as a side effect of the way we built source intersections, we can actually test the behavior of the simulation on complicated road networks, but initially, it makes sense to do some very simple tests.

Of course, none of the real intersections work, but we can get going with just source intersections and sink intersections, testing the code with something like this:

intersection A 1.0 source 10.0
intersection B 1.0 sink
road A B 5.0

We can even get ambitious, adding multiple sources or sinks:

intersection A 1.0 source 10.0
intersection B 1.0 sink
intersection C 1.0 sink
road A B 5.0
road A C 10.0

Once this works, the next obvious step is to add some intermediate non-stop intersections

intersection A 1.0 source 10.0
intersection B 1.0 source 10.0
intersection C 1.0
intersection D 1.0 sink
intersection E 1.0 sink
road A C 5.0
road B C 5.0
road C D 5.0
road C E 5.0

An interesting question is, what happens if we add some cycles to the road network, allowing cars to go around the block?

intersection A 1.0 source 10.0
intersection B 1.0 source 10.0
intersection C 1.0
intersection D 1.0 sink
intersection E 1.0 sink
road A B 5.0
road A C 5.0
road B A 5.0
road B C 5.0
road C A 5.0
road C B 5.0
road C D 5.0
road C E 5.0

At this point, it is clear that a simple trace of activity with outputs from each intersection each time a car passes through isn't very interesting except as a proof that our mechanism is doing something.