For instance, in the example of the double click above, the
time for recognizing clicks and performing aritmetical operations
is considered 0 w.r.t. the time between two consecutive clicks.
For many applications, this hypothesis is reasonable in practice:
the operations in the processor
are several order of magnitude faster than external events
The system that require specifying and guarranteeing an
upper boud to execution time fall into a specialized area
of concurrency called real-time systems.
Some of the timed classes
Assume two consecutive clicks take place at times
t1 and t2:
e1 e2
|------|------|------|------|------|------> time
0 1 2 3 4 5 (clock ticks)
public interface Timed {
void pretick();
void tick();
}
public class TimeManager extends Thread
implements AdjustmentListener{
volatile int delay; // length of clock cycle
ImmutableList clocked = null;
public TimeManager(int d) {delay = d;}
public void addTimed(Timed el) {
clocked = ImmutableList.add(clocked,el);
}
public void removeTimed(Timed el) {
clocked = ImmutableList.remove(clocked,el);
}
public void adjustmentValueChanged(AdjustmentEvent e) {
delay = e.getValue();
}
public void run () {
try {
while(true) {
try {
Enumeration e = ImmutableList.elements(clocked);
while (e.hasMoreElements()) //pretick broadcast
((Timed)e.nextElement()).pretick();
e = ImmutableList.elements(clocked);
while (e.hasMoreElements()) //tick broadcast
((Timed)e.nextElement()).tick();
} catch (TimeStop s) {
System.out.println("*** TimeStop");
return;
}
Thread.sleep(delay);
}
} catch (InterruptedException e){}
}
}
/**
*------------CHUTE-----------------
*/
class Chute implements ParcelMover,Timed {
protected int i,T,direction;
protected Parcel current = null;
ParcelMover next = null;
Chute(int len, int dir) {
T = len;
direction = dir;
}
// package enters chute
public void enter(Parcel p) throws TimeStop {
if (current!=null) throw new TimeStop();
current = p; i = 0;
}
public void pretick() throws TimeStop {
if (current==null) return;
if (i == T) {
next.enter(current); // package leaves chute
current = null;
}
}
public void tick(){
if (current==null) return;
++i;
current.move(direction);
}
}
/**
*----------------Switch -------------------
*/
class Switch extends Chute implements SwitchControl {
ParcelMover left = null;
ParcelMover right = null;
private ParcelCanvas display;
private int gate;
Switch(int len, int dir, int g, ParcelCanvas d )
{ super(len,dir); display = d; gate = g;}
public void setSwitch(int direction) {
if (current==null) { // nothing passing through switch
display.setGate(gate,direction);
if (direction==0)
next = left;
else
next = right;
}
}
}
/**
*----------------DestinationBin -------------------
*/
class DestinationBin implements ParcelMover, Timed {
private Parcel current;
private boolean flash = false;
private boolean off = false;
private int tickCount = 0;
private int destination;
static int FLASHPERIOD = 10;
DestinationBin(int destination)
{this.destination = destination;}
public void enter(Parcel p) throws TimeStop {
if (current!=null) current.remove();
current = p;
flash = !(p.destination == destination);
}
public void pretick(){};
public void tick() {
tickCount = (tickCount+1)%FLASHPERIOD;
if (tickCount==0 && flash) {
off = !off;
current.hide(off);
}
}
}
In this system, the sensors are not timed objects, essentially because they are "very thin":
a parcel enters and exit a sensor within one clock cycle
/**
*----------------SensorController-------------------
*/
class SensorController implements ParcelMover {
ParcelMover next;
SwitchControl controlled;
protected int level;
SensorController(int level){this.level=level;}
// package enters and leaves within one clock cycle
public void enter(Parcel p) throws TimeStop {
route(p.destination);
next.enter(p);
}
protected void route(int destination) {
int dir = (destination>>level) & 1;
controlled.setSwitch(dir);
}
}
class Alien extends Sprite {
int dir;
Alien(int x) {
super(alien,x,0,SpaceInvaders.theDisplay,SpaceInvaders.theTicker);
setIncrement(1+(int)(Math.random()*10.0));
int choice = (int) (Math.random()*10.0);
if (choice<3) dir = SOUTHWEST;
else if (choice<7) dir = SOUTH;
else dir = SOUTHEAST;
}
public void hit() {
new Explosion(this);
SpaceInvaders.score.alienHit();
SpaceInvaders.detector.removeAlien(this);
remove();
}
public void tick() {
move(dir);
if ((posY()>=AREA.height-height-1)||(posX()>=AREA.width-width-1)){
SpaceInvaders.detector.removeAlien(this);
remove();
}
}
}
class CollisionDetector implements Timed {
ImmutableList aliens = null;
ImmutableList missiles = null;
CollisionDetector(){
SpaceInvaders.theTicker.addTimed(this);
}
public void addAlien(Sprite a) {
aliens = ImmutableList.add(aliens,a);
}
public void removeAlien(Sprite a) {
aliens = ImmutableList.remove(aliens,a);
}
public void addMissile(Sprite m) {
missiles = ImmutableList.add(missiles,m);
}
public void removeMissile(Sprite m) {
missiles = ImmutableList.remove(missiles,m);
}
public void pretick(){
Enumeration e = ImmutableList.elements(aliens);
while(e.hasMoreElements()){
Sprite alien = (Sprite)e.nextElement();
if (alien.collide(SpaceInvaders.ship)) {
SpaceInvaders.ship.hit();
alien.hit();
}
Enumeration m = ImmutableList.elements(missiles);
while(m.hasMoreElements()){
Sprite missile = (Sprite)m.nextElement();
if (alien.collide(missile)) {
alien.hit();
missile.hit();
}
}
}
}
public void tick() {}
}