// traffic simulation // this time, just the cars, but they move at high speed for the first 200 pixels, and a lower speed for the rest. // they are supposed to not get within 20 pixels of each other, but this seems not to be working. import colors.*; import geometry.*; import idraw.*; // interface for objects in the simulation world. // all objects in the world must be able to respond to onTick and draw. interface IObj { void onTick(); void draw(Canvas c); } class NullObj implements IObj { void onTick() { return; } void draw(Canvas c) { return; } } // composite object. draw(), onTick() are sent to first, then second. class ConsObj implements IObj { IObj first; IObj second; ConsObj (IObj first, IObj second) { this.first = first; this.second = second; } void onTick() { this.first.onTick(); this.second.onTick(); return; } void draw(Canvas c) { this.first.draw(c); this.second.draw(c); return; } } // interface to avoid introducing null interface ICar extends IObj { int getRearLoc(); } // class for the non-existent car in front of the first real car // it is always moving and sits at x=999999; otherwise it doesn't do anything. // I'd like this to say "implements ICar extends NullObj", but this doesn't seem to work. class NullCar implements ICar { NullCar(){ } void onTick() { return; } void draw(Canvas c) { return; } int getRearLoc(){ return 999999; } } // A real car. Enters at x=0, records the time since its creation. class Car implements ICar { Posn p; // position of left (rear) bumper int time; // time since its creation ICar carAhead; TWorld w; int speed1 = 20; int speed2 = 4; int gap = 20; int WIDTH = 20; int HEIGHT = 10; IColor color = new Blue(); // create a car at Posn p, following carAhead. Car(int x, ICar carAhead, TWorld w) { this.p = new Posn(x, w.HEIGHT-this.HEIGHT); this.carAhead = carAhead; this.w = w; this.time = 0; w.addCar(this); // register the car } void onTick(){ this.time = this.time+1; int nextx = 0; int carAheadRearLoc = this.carAhead.getRearLoc(); if (this.p.x < 200) { // we are to the left of the halfway mark nextx = this.p.x+this.speed1; } else { // we are to the right of the 500 px mark nextx = this.p.x+this.speed2; // this.color = new Green(); } if (carAheadRearLoc - nextx < this.gap + this.WIDTH) { // this.color = new Yellow(); nextx = carAheadRearLoc - this.gap - this.WIDTH; } else {} this.p = new Posn (nextx, this.p.y); return; } void draw(Canvas c){ c.drawRect(this.p, this.WIDTH, this.HEIGHT, this.color); return; } int getRearLoc(){ return this.p.x; } } // create a new car into world w every period ticks class CarMaker extends NullObj { TWorld w; int period; int counter; ICar previousCar; CarMaker (int period, TWorld w) { this.w = w; this.period = period; this.counter = 0; this.previousCar = new NullCar(); w.addObj(this); // register to receive ticks only } void onTick () { if (this.counter >= this.period) { // time to create a new car. Also reset the counter. Car newCar = new Car(0, this.previousCar, w); this.previousCar = newCar; this.counter = 0; return; } else { this.counter = this.counter + 1; return; } } } class TWorld extends World { int WIDTH = 1000; int HEIGHT = 100; double rate = 0.25; IObj cars = new NullObj(); IObj lights = new NullObj(); IObj otherObjs = new NullObj(); TWorld (){ } void addCar(Car c){ this.cars = new ConsObj(this.cars, c); } /* void addLight(TrafficLight t) { this.lights = new ConsObj(this.lights, t); } */ void addObj(IObj o) { this.otherObjs = new ConsObj(this.otherObjs, o); } void start(){ this.bigBang(this.WIDTH, this.HEIGHT, this.rate); } void onTick(){ this.cars.onTick(); // this.lights.onTick(); this.otherObjs.onTick(); return; } void draw(){ this.cars.draw(this.theCanvas); // this.lights.draw(this.theCanvas); return; } void onKeyEvent(String s){ return; } } class Examples { TWorld w = new TWorld(); Examples () { // ICar car1 = new Car(100, new NullCar(), w); // ICar car2 = new Car(0, car1, w); CarMaker carMaker1 = new CarMaker(2,w); w.start(); } }