Road Rage Simulation

Road Rage is becoming a major problem today. People are spending more and more time waiting in traffic and at traffic lights. This simulation allows you to simulate traffic flows at a traffic light under three different light-changing strategies. The first strategy is simply fixed at 5 seconds per direction. The second is fairly realistic, keeping a light green as long as cars are still coming, up to 30 seconds maximum. The third strategy is based on a measure of "madness". The assumption is that one driver waiting ten minutes is madder than ten drivers waiting one minute. So lights change when another direction gets "madder". Try it!

Run the Simulation!

Stop.java - source file

   1: // Created by Lance O'Hara and his dad
   2: // october and november 2003
   3: 
   4: import java.awt.BorderLayout;
   5: import java.awt.Canvas;
   6: import java.awt.Color;
   7: import java.awt.Dimension;
   8: import java.awt.Font;
   9: import java.awt.Graphics;
  10: import java.awt.Toolkit;
  11: import java.awt.event.ActionEvent;
  12: import java.awt.event.ActionListener;
  13: import java.text.SimpleDateFormat;
  14: import java.util.Date;
  15: import java.util.Iterator;
  16: import java.util.LinkedList;
  17: import java.util.Timer;
  18: import java.util.TimerTask;
  19: 
  20: import javax.swing.BorderFactory;
  21: import javax.swing.Box;
  22: import javax.swing.ButtonGroup;
  23: import javax.swing.JApplet;
  24: import javax.swing.JButton;
  25: import javax.swing.JFrame;
  26: import javax.swing.JLabel;
  27: import javax.swing.JPanel;
  28: import javax.swing.JRadioButton;
  29: import javax.swing.JSeparator;
  30: import javax.swing.JSlider;
  31: import javax.swing.border.Border;
  32: import javax.swing.event.ChangeEvent;
  33: import javax.swing.event.ChangeListener;
  34: 
  35: /**
  36:  * main program, can be run as applet (internet)
  37:  */
  38: public class Stop extends JApplet implements ChangeListener, ActionListener
  39: {
  40:     // constants to adjust behavior
  41:     
  42:     private static final int LEFT = 0;
  43:     private static final int RIGHT = 1;
  44:     private static final int TOP = 2;
  45:     private static final int BOTTOM = 3;
  46:     private static final int DIRECTIONS = 4;
  47: 
  48:     private static final int green = 0;
  49:     private static final int red = 1;
  50:         
  51:     // Traffic flows per minute
  52:     private static final int MINRATE = 1;
  53:     private static final int MAXRATE = 5000;
  54:     
  55:     private static final int MINSPEED = 10;    //mph
  56:     private static final int MAXSPEED = 20;    //mph
  57:     private static final int CARSIZE = 15;  //feet
  58:     
  59:     private static final int FIXEDLIGHTTIME = 5;  //seconds
  60:     private static final int LONGESTLIGHTTIME = 30;
  61: 
  62:     private static final Color HAPPYCOLOR = Color.blue;
  63:     private static final Color MILDCOLOR = Color.yellow;
  64:     private static final Color MADCOLOR = new Color(243, 103, 13);
  65:     private static final Color LIVIDCOLOR = Color.red;
  66:     
  67:     private static final int HAPPY = 4;
  68:     private static final int MILD = 10;
  69:     private static final int MAD = 20;
  70:     
  71:     //items are for each direction (4)    
  72:     private JSlider sliders[];
  73:     private int rates[];        //cars per hour
  74:     private int colors[];       //traffic light colors
  75:     private int done[];     // number of cars gone off screen
  76:     private int count[];    // number of cars still on screen or waiting to get on screen
  77:     private double madness[];
  78:     private double totalmadness[];
  79:     private MyCar farthestCar[];
  80:     
  81:     // strategy buttons
  82:     private JRadioButton strategy1;
  83:     private JRadioButton strategy2;
  84:     private JRadioButton strategy3;
  85:     
  86:     //strategies
  87:     private static final int FIXED_STRATEGY = 1;
  88:     private static final int USUAL_STRATEGY = 2;
  89:     private static final int MAD_STRATEGY = 3;
  90:     
  91:     private int strategy = FIXED_STRATEGY;
  92:     
  93:     private int whoIsGreen;   // one of top bottom, left or right
  94:     private int beenRed;    //how long light has been red
  95:     private MyCar keyCar = new MyCar();     //used for the key
  96:     
  97:     private MyCanvas canvas;    //the big drawing without the sliders
  98:     
  99:     private long start;     // when program started
 100:     private long ticks;     //number of ticks since started
 101:     private JButton stop;   //stop button
 102:     private Timer timer;    //causes "run" to be called every second
 103:     
 104:     private int lightsize = 5;      
 105:     private int streetsize = 15;
 106:     
 107:     private Font infoFont = new Font("fixed", Font.PLAIN, 12);
 108:     private Font clockFont = new Font("fixed", Font.BOLD, 36);
 109:     private Font keyFont = new Font("fixed", Font.ITALIC, 12);
 110:     
 111:     private SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
 112:     
 113:     // all cars in every direction including cars trying to get on screen
 114:     //does not include cars that have gone off the screen
 115:     private LinkedList cars = new LinkedList();
 116:         
 117:     /**
 118:      * only called from an applet
 119:      */
 120:     public void init()      
 121:     {
 122:         // Called from applet
 123:         getContentPane().add(initialize());
 124: 
 125:         int h = getHeight() / 10;
 126:         int w = getWidth() / 10;
 127:         startClock(4 * w, 4 * h);
 128:    }
 129: 
 130:     /**
 131:      * creates all buttons, objects, everything
 132:      */
 133:     public JPanel initialize()
 134:     {
 135:         JPanel mainpanel = new JPanel(new BorderLayout());
 136:         
 137:         JPanel panel = new JPanel(new BorderLayout());
 138:         Border pad = BorderFactory.createEmptyBorder(5, 5, 5, 5);
 139:         panel.setBorder(pad);
 140:         
 141:         rates = new int[DIRECTIONS];
 142:         colors = new int[DIRECTIONS];
 143:         count = new int[DIRECTIONS];
 144:         done = new int[DIRECTIONS];
 145:         madness = new double[DIRECTIONS];
 146:         totalmadness = new double[DIRECTIONS];
 147:         farthestCar = new MyCar[DIRECTIONS];
 148:         
 149:         for (int i = 0; i < DIRECTIONS; i++)
 150:         {
 151:             rates[i] = 100;
 152:             colors[i] = red;
 153:         }               
 154:         whoIsGreen = RIGHT;
 155:         colors[whoIsGreen] = green;
 156:         rates[RIGHT] = 1000;
 157:         
 158:         start = System.currentTimeMillis();
 159:         
 160:         sliders = new JSlider[DIRECTIONS];
 161:         
 162:         sliders[LEFT] = new JSlider(JSlider.VERTICAL, MINRATE, MAXRATE, rates[LEFT]);
 163:         sliders[LEFT].addChangeListener(this);
 164:         Box leftbox = Box.createVerticalBox();
 165:         leftbox.add(Box.createGlue());
 166:         leftbox.add(sliders[LEFT]);
 167:         leftbox.add(Box.createGlue());
 168:         panel.add(leftbox, BorderLayout.WEST);
 169:         
 170:         sliders[TOP] = new JSlider(JSlider.HORIZONTAL, MINRATE, MAXRATE, rates[TOP]);
 171:         sliders[TOP].addChangeListener(this);
 172:         JPanel toppanel = new JPanel();
 173:         toppanel.add(sliders[TOP]);
 174:         panel.add(toppanel, BorderLayout.NORTH);
 175:         
 176:         sliders[RIGHT] = new JSlider(JSlider.VERTICAL, MINRATE, MAXRATE, rates[RIGHT]);
 177:         sliders[RIGHT].addChangeListener(this);
 178:         Box rightbox = Box.createVerticalBox();
 179:         rightbox.add(Box.createGlue());
 180:         rightbox.add(sliders[RIGHT]);
 181:         rightbox.add(Box.createGlue());
 182:         panel.add(rightbox, BorderLayout.EAST);
 183:         
 184:         sliders[BOTTOM] = new JSlider(JSlider.HORIZONTAL, MINRATE, MAXRATE, rates[BOTTOM]);
 185:         sliders[BOTTOM].addChangeListener(this);
 186:         JPanel bottompanel = new JPanel();
 187:         bottompanel.add(sliders[BOTTOM]);
 188:         panel.add(bottompanel, BorderLayout.SOUTH);
 189:         
 190:         canvas = new MyCanvas();
 191:         panel.add(canvas, BorderLayout.CENTER);
 192:         
 193:         addRadioBox(mainpanel);
 194:        
 195:         mainpanel.add(panel, BorderLayout.CENTER);
 196:         return mainpanel;
 197:     }
 198:     
 199:     /**
 200:      * creates stop button and strategy buttons
 201:      */
 202:     private void addRadioBox(JPanel panel)
 203:     {
 204:         Box box = Box.createVerticalBox();
 205:         box.add(new JSeparator(JSeparator.HORIZONTAL));
 206:         
 207:         strategy1 = new JRadioButton("1. Fixed interval (" + FIXEDLIGHTTIME + " seconds)");
 208:         strategy1.addActionListener(this);
 209:         strategy1.setSelected(true);
 210:         strategy2 = new JRadioButton("2. Keep green up to " + LONGESTLIGHTTIME + " seconds");
 211:         strategy2.addActionListener(this);
 212:         strategy3 = new JRadioButton("3. Stop when another direction is 'madder'");
 213:         strategy3.addActionListener(this);
 214:         
 215:         ButtonGroup group = new ButtonGroup();
 216:         group.add(strategy1);
 217:         group.add(strategy2);
 218:         group.add(strategy3);
 219:         
 220:         JLabel label = new JLabel("                     Light Strategy: ");
 221:         
 222:         stop = new JButton("Stop");
 223:         stop.addActionListener(this);
 224:         
 225:         Box radiobox = Box.createHorizontalBox();
 226:         radiobox.add(stop);
 227:         radiobox.add(label);
 228:         radiobox.add(strategy1);
 229:         radiobox.add(strategy2);
 230:         radiobox.add(strategy3);
 231:         
 232:         box.add(radiobox);
 233:         panel.add(box, BorderLayout.SOUTH);
 234:     }
 235:     
 236:     /**
 237:      * called when any slider is moved
 238:      */
 239:     public void stateChanged(ChangeEvent e)
 240:     {
 241:         Object obj = e.getSource();
 242:         for (int i = 0; i < DIRECTIONS; i++)
 243:         {
 244:             if (sliders[i].equals(obj))
 245:             {
 246:                 // Don't do anything if they are still changing it
 247:                 if (!sliders[i].getValueIsAdjusting())
 248:                 {
 249:                     rates[i] = sliders[i].getValue();
 250:                     canvas.repaint();
 251:                 }
 252:             }
 253:         }
 254:     }
 255:     
 256:     /**
 257:      * called when any button is pushed
 258:      */
 259:     public void actionPerformed(ActionEvent e)
 260:     {
 261:         Object obj = e.getSource();
 262:         if (obj.equals(strategy1))
 263:         {
 264:             strategy = FIXED_STRATEGY;
 265:         }
 266:         else if (obj.equals(strategy2))
 267:         {
 268:             strategy = USUAL_STRATEGY;
 269:         }
 270:         else if (obj.equals(strategy3))
 271:         {
 272:             strategy = MAD_STRATEGY;
 273:         }
 274:         else if (obj.equals(stop))
 275:         {
 276:             timer.cancel();
 277:         }
 278:     }
 279: 
 280:     private class MyCanvas extends Canvas
 281:     {    
 282:         /**
 283:          * called when the screen redraws
 284:          */
 285:         public void paint(Graphics g)
 286:         {
 287:             int w = getWidth() / 2;
 288:             int h = getHeight() / 2;
 289:             drawstreets(g, w, h);   //draw black and yellow in street
 290:             drawclock(g, 5, 30);    //draws clock
 291:             showKey(g, 5, 60);      //key of madness
 292:             showinfo(g, w, h);      //rate, madness, cars of each direction
 293:             
 294:             Iterator iter = cars.iterator();
 295:             while (iter.hasNext())
 296:             {
 297:                 MyCar car = (MyCar) iter.next();
 298:                 car.draw(g, w, h);  //draw the next car
 299:             }
 300:             
 301:             drawlight(g, w, h);     //draw traffic light last
 302:         }
 303:         
 304:         private Color getcolor(int color)
 305:         {
 306:             if (color == green) return Color.green;
 307:             return Color.red;
 308:         }
 309: 
 310:         /**
 311:          *draw traffic light at centerx, centery 
 312:          */
 313:         private void drawlight(Graphics g, int centerx, int centery)
 314:         {
 315:             g.setColor(getcolor(colors[LEFT]));
 316:             g.fillRect(centerx-3*lightsize, centery-lightsize, 2*lightsize, 2*lightsize);  //left
 317:             g.setColor(getcolor(colors[BOTTOM]));
 318:             g.fillRect(centerx-lightsize, centery+lightsize, 2*lightsize, 2*lightsize);    //bottom
 319:             g.setColor(getcolor(colors[RIGHT]));
 320:             g.fillRect(centerx+lightsize, centery-lightsize, 2*lightsize, 2*lightsize);    //right
 321:             g.setColor(getcolor(colors[TOP]));
 322:             g.fillRect(centerx-lightsize, centery-3*lightsize, 2*lightsize, 2*lightsize);  //top
 323:         
 324:             g.setColor(Color.gray);
 325:             g.fillOval(centerx-2*lightsize, centery-2*lightsize, 4*lightsize, 4*lightsize);
 326:         }
 327:         
 328:         /**
 329:          * draw both streets with yellow stripes
 330:          */    
 331:         private void drawstreets(Graphics g, int centerx, int centery)
 332:         {
 333:             g.setColor(Color.black);
 334:             g.fillRect(centerx-streetsize, 0, 2*streetsize, 2*centery);
 335:             g.fillRect(0, centery-streetsize, 2*centerx, 2*streetsize);
 336:         
 337:             g.setColor(Color.yellow);
 338:             g.drawLine(centerx, 0, centerx, 2*centery);
 339:             g.drawLine(0, centery, 2*centerx, centery);
 340:         }
 341:         
 342:         /**
 343:          * displays "info" for each direction
 344:          */
 345:         private void showinfo(Graphics g, int centerx, int centery)
 346:         {
 347:             g.setFont(infoFont);
 348:             g.setColor(Color.black);
 349:             
 350:             g.drawString("Rate: " + rates[TOP] + " cars / hour",
 351:                 centerx + streetsize + 20, 20);
 352:             g.drawString("Rate: " + rates[BOTTOM] + " cars / hour",
 353:                 centerx + streetsize + 20, 3 * centery / 2 + 20);
 354:             g.drawString("Rate: " + rates[LEFT] + " cars / hour",
 355:                 20, centery + streetsize + 20);
 356:             g.drawString("Rate: " + rates[RIGHT] + " cars / hour",
 357:                 3 * centerx / 2 + 20, centery + streetsize + 20);
 358:                 
 359:             Iterator iter = cars.iterator();
 360:             for (int i = 0; i < DIRECTIONS; i++)
 361:             {
 362:                 count[i] = 0;
 363:                 madness[i] = 0;
 364:             }
 365:             while (iter.hasNext())
 366:             {
 367:                 MyCar car = (MyCar) iter.next();
 368:                 int dir = car.fromDirection;
 369:                 count[dir] = count[dir] + 1;
 370:                 madness[dir] = madness[dir] + car.mad;
 371:             }
 372:             
 373:             g.drawString("Cars: " + count[TOP] + " (" + done[TOP] + " done)",
 374:                 centerx + streetsize + 20, 40);
 375:             g.drawString("Cars: " + count[BOTTOM] + " (" + done[BOTTOM] + " done)",
 376:                 centerx + streetsize + 20, 3 * centery / 2 + 40);
 377:             g.drawString("Cars: " + count[LEFT] + " (" + done[LEFT] + " done)",
 378:                 20, centery + streetsize + 40);
 379:             g.drawString("Cars: " + count[RIGHT] + " (" + done[RIGHT] + " done)",
 380:                 3 * centerx / 2 + 20, centery + streetsize + 40);
 381:                 
 382:             g.drawString("Madness: " + (int) madness[TOP] + " (" + (int) (totalmadness[TOP] / ticks) + " avg)",
 383:                 centerx + streetsize + 20, 60);
 384:             g.drawString("Madness: " + (int) madness[BOTTOM] + " (" + (int) (totalmadness[BOTTOM] / ticks) + " avg)",
 385:                 centerx + streetsize + 20, 3 * centery / 2 + 60);
 386:             g.drawString("Madness: " + (int) madness[LEFT] + " (" + (int) (totalmadness[LEFT] / ticks) + " avg)",
 387:                 20, centery + streetsize + 60);
 388:             g.drawString("Madness: " + (int) madness[RIGHT] + " (" + (int) (totalmadness[RIGHT] / ticks) + " avg)",
 389:                 3 * centerx / 2 + 20, centery + streetsize + 60);
 390:         }        
 391:         
 392:         /**
 393:          * draws clock
 394:          */
 395:         private void drawclock(Graphics g, int x, int y)
 396:         {
 397:             g.setFont(clockFont);
 398:             g.setColor(Color.red);
 399:             long curr = System.currentTimeMillis();
 400:             Date now = new Date(curr - start);
 401:             g.drawString("Duration: " + sdf.format(now), x, y);
 402:         }
 403:         
 404:         /**
 405:          * draws key showing madness levels
 406:          */
 407:         private void showKey(Graphics g, int x, int y)
 408:         {
 409:             g.setFont(keyFont);
 410: 
 411:             // Draw happy car
 412:             keyCar.mad = 0;
 413:             keyCar.drawcar(g, x, y - streetsize, 2 * streetsize, streetsize);
 414:             g.setColor(Color.black);
 415:             g.drawString("Calm", x + 2 * streetsize, y - 5);
 416: 
 417:             // Draw mild car
 418:             keyCar.mad = HAPPY + 1;
 419:             keyCar.drawcar(g, x, y + 5, 2 * streetsize, streetsize);
 420:             g.setColor(Color.black);
 421:             g.drawString("Mild", x + 2 * streetsize, y + streetsize);
 422: 
 423:             // Draw mad car
 424:             keyCar.mad = MILD + 1;
 425:             keyCar.drawcar(g, x, y + streetsize + 10, 2 * streetsize, streetsize);
 426:             g.setColor(Color.black);
 427:             g.drawString("Mad", x + 2 * streetsize, y + 2 * streetsize + 5);
 428: 
 429:             // Draw livid car
 430:             keyCar.mad = MAD + 1;
 431:             keyCar.drawcar(g, x, y + 2*streetsize + 15, 2 * streetsize, streetsize);
 432:             g.setColor(Color.black);
 433:             g.drawString("Livid", x + 2 * streetsize, y + 3 * streetsize + 10);
 434:         }
 435:     }
 436:  
 437:     /**
 438:      *print same info as drawinfo(), but to screen 
 439:      */
 440:     private void printinfo()
 441:     {
 442:         long curr = System.currentTimeMillis();
 443:         Date now = new Date(curr - start);
 444:         System.out.println("Duration: " + sdf.format(now));
 445:                     
 446:         System.out.println("TOP Rate: " + rates[TOP] + " cars / hour");
 447:         System.out.println("Cars: " + count[TOP] + " (" + done[TOP] + " done)");
 448:         System.out.println("Madness: " + (int) madness[TOP] + " (" + (int) (totalmadness[TOP] / ticks) + " avg)");
 449:                 
 450:         System.out.println("BOTTOM Rate: " + rates[BOTTOM] + " cars / hour");
 451:         System.out.println("Cars: " + count[BOTTOM] + " (" + done[BOTTOM] + " done)");
 452:         System.out.println("Madness: " + (int) madness[BOTTOM] + " (" + (int) (totalmadness[BOTTOM] / ticks) + " avg)");
 453:         
 454:         System.out.println("LEFT Rate: " + rates[LEFT] + " cars / hour");
 455:         System.out.println("Cars: " + count[LEFT] + " (" + done[LEFT] + " done)");
 456:         System.out.println("Madness: " + (int) madness[LEFT] + " (" + (int) (totalmadness[LEFT] / ticks) + " avg)");
 457:         
 458:         System.out.println("RIGHT Rate: " + rates[RIGHT] + " cars / hour");
 459:         System.out.println("Cars: " + count[RIGHT] + " (" + done[RIGHT] + " done)");
 460:         System.out.println("Madness: " + (int) madness[RIGHT] + " (" + (int) (totalmadness[RIGHT] / ticks) + " avg)");
 461:         
 462:         System.out.println();
 463:     }        
 464: 
 465:     private class MyCar
 466:     {
 467:         int fromDirection;  // One of LEFT, RIGHT, TOP, BOTTOM
 468:         double position;   // -1.0 just started, 1.0 already done, 0.0 at the light
 469:         double speed;
 470:         double mad;
 471:  
 472:         /**
 473:          * draw a car, have to figure out which direction its going
 474:          */
 475:         public void draw(Graphics g, int w, int h)
 476:         {
 477:             switch (fromDirection)
 478:             {
 479:                 case LEFT:
 480:                     drawcar(g, w - position*w - 2*streetsize, h,
 481:                         2*streetsize, streetsize);
 482:                     break;
 483: 
 484:                 case RIGHT:
 485:                     drawcar(g, w + position*w + streetsize, h - streetsize,
 486:                         2*streetsize, streetsize);
 487:                     break;
 488: 
 489:                 case TOP:
 490:                     drawcar(g, w - streetsize, h - position*h - 2*streetsize,
 491:                         streetsize, 2*streetsize);
 492:                     break;
 493: 
 494:                 case BOTTOM:
 495:                     drawcar(g, w, h + position*h + streetsize,
 496:                         streetsize, 2*streetsize);            
 497:                     break;
 498:             }
 499:         }
 500:         
 501:         /**
 502:          * draw a car and color it with its madness
 503:          */
 504:         private void drawcar(Graphics g, double x, double y, int w, int h)
 505:         {
 506:             g.setColor(Color.white);
 507:             g.fillRect((int) x+w/10, (int) y+h/10, w*8/10, h*8/10);
 508:             
 509:             if (mad < HAPPY)
 510:             {
 511:                 g.setColor(HAPPYCOLOR);
 512:             }
 513:             else if (mad < MILD)
 514:             {
 515:                 g.setColor(MILDCOLOR);
 516:             }
 517:             else if (mad < MAD)
 518:             {
 519:                 g.setColor(MADCOLOR);
 520:             }
 521:             else
 522:             {
 523:                 g.setColor(LIVIDCOLOR);
 524:             }
 525:             
 526:             g.fillRect((int) x+2*w/10, (int) y+2*h/10, w*6/10, h*6/10);            
 527:         }
 528:     }
 529:     
 530:     /**
 531:      * call run() every 1000 milliseconds (1 second)
 532:      */
 533:     private void startClock(int w, int h)
 534:     {
 535:         TimerTask task = new MyTimerTask(w, h);
 536:         timer = new Timer();
 537:         timer.scheduleAtFixedRate(task, 0, 1000); // Once a second  - drives the clock
 538:     }
 539:     
 540:     private class MyTimerTask extends TimerTask
 541:     {
 542:         int w;
 543:         int h;
 544:         
 545:         public MyTimerTask(int width, int height)
 546:         {
 547:             w = width;
 548:             h = height;
 549:         }
 550:         
 551:         /**
 552:          * called automatically once a second
 553:          */
 554:         public void run()
 555:         {
 556:             double scale = 0;
 557:             
 558:             //count clock ticks, print stuff to screen every 5 min
 559:             ticks++;
 560:             if (ticks % 300 == 0)
 561:             {
 562:                 printinfo();
 563:             }
 564:             
 565:             //add up madness, for averages
 566:             for (int i = 0; i < DIRECTIONS; i++)
 567:             {
 568:                 totalmadness[i] = totalmadness[i] + madness[i];
 569:             }
 570: 
 571:             // move all existing cars
 572:             Iterator iter = cars.iterator();
 573:             while (iter.hasNext())
 574:             {
 575:                 MyCar car = (MyCar) iter.next();
 576:                 car.mad = car.mad * 1.05;
 577:                 
 578:                 double feet = car.speed * 5280.0/3600.0;    // Convert mph to feet/second
 579:                 scale = CARSIZE / (2.0 * streetsize);
 580:                 switch (car.fromDirection)
 581:                 {
 582:                     case LEFT:
 583:                     case RIGHT:
 584:                         scale = scale * w;
 585:                         break;                   
 586:                     case TOP:
 587:                     case BOTTOM:
 588:                         scale = scale * h;
 589:                         break;
 590:                 }
 591:                 
 592:                 // Stop for a red light
 593:                 if (colors[car.fromDirection] == red)
 594:                 {
 595:                     double pos = car.position - lightsize / scale;
 596:                     if (pos > 0 && pos < feet / scale)
 597:                     {
 598:                         if (car.mad == 0)
 599:                         {
 600:                             //start to get mad when waiting at light
 601:                             car.mad = 1;
 602:                         }
 603:                         //car.position = 2 * lightsize / scale;   // Move up to the light and stop there
 604:                         continue;  // Have to wait for a green light
 605:                     }
 606:                 }
 607:                 
 608:                 // Move the car (important)
 609:                 car.position = car.position - feet / scale;
 610:                 
 611:                 // You're not mad after the light
 612:                 if (car.position < 0)
 613:                 {
 614:                     car.mad = 0;
 615:                 }
 616:                 
 617:                 // Make sure we don't catch up to another car!
 618:                 Iterator iter2 = cars.iterator();
 619:                 while (iter2.hasNext())
 620:                 {
 621:                     MyCar car2 = (MyCar) iter2.next();
 622:                     
 623:                     // Only look at cars ahead of me
 624:                     if (car2.equals(car))
 625:                     {
 626:                         break;
 627:                     }
 628:                     
 629:                     if (car.fromDirection == car2.fromDirection)
 630:                     {
 631:                         double last = car2.position + 1.5 * CARSIZE / scale;
 632:                         if (last > car.position)
 633:                         {
 634:                             car.position = last;
 635:                             if (car.mad == 0)
 636:                             {
 637:                                 //start to get mad when waiting for car infront of it
 638:                                 car.mad = 1;
 639:                             }
 640:                         }
 641:                     }
 642:                 }
 643:                 
 644:                 //remove cars that fall off
 645:                 if (car.position < -1)
 646:                 {
 647:                     iter.remove();
 648:                     cars.remove(car);
 649:                     done[car.fromDirection]++;
 650:                 }
 651:             }
 652:             
 653:             //create new cars
 654:             for (int i = 0; i < DIRECTIONS; i++)
 655:             {
 656:                 double chances = rates[i] / 3600.0; // Seconds per hour
 657:                 //math.random returns a number from 0 to 1
 658:                 if (Math.random() < chances)
 659:                 {
 660:                     // Yes, create another car!
 661:                     MyCar car = new MyCar();
 662:                     car.position = 1;   // may have to wait to get on screen
 663:                     car.fromDirection = i;
 664:                     car.speed = MINSPEED + (MAXSPEED - MINSPEED) * Math.random();
 665:                     car.mad = 0;
 666:                     
 667:                     // Make sure we don't pass the farthest car in this direction
 668:                     if (farthestCar[i] != null)
 669:                     {
 670:                         double last = farthestCar[i].position + 1.5 * CARSIZE / scale;
 671:                         if (last > car.position)
 672:                         {
 673:                             if (car.mad == 0)
 674:                             {
 675:                                 //have to wait to get on screen
 676:                                 car.mad = 1;
 677:                             }
 678:                             car.position = last;
 679:                         }
 680:                     }
 681:                     
 682:                     //add new car to list of cars
 683:                     cars.add(car);
 684:                     farthestCar[i] = car;
 685:                 }
 686:             }
 687:             
 688:             // See if it's time to change the light
 689:             if (changelight(whoIsGreen, scale))
 690:             {
 691:                 //yes its time
 692:                 colors[whoIsGreen] = red;
 693:                 whoIsGreen = whoIsGreen + 1;
 694:                 beenRed = 0;
 695:                 if (whoIsGreen == DIRECTIONS)
 696:                 {
 697:                     whoIsGreen = 0;
 698:                 }
 699:                 colors[whoIsGreen] = green;
 700:             }
 701:             
 702:             //redraw everything
 703:             canvas.repaint();
 704:         }
 705:         
 706:         /**
 707:          * decide whether or not its time to change light to red
 708:          * return true if its time 
 709:          */
 710:         private boolean changelight(int dir, double scale)
 711:         {
 712:             // keeps track how long the light has been red in seconds
 713:             beenRed = beenRed + 1;
 714:             
 715:             switch (strategy)
 716:             {
 717:                 case FIXED_STRATEGY :
 718:                     if (beenRed > FIXEDLIGHTTIME)
 719:                     {
 720:                         return true;
 721:                     }
 722:                     break;
 723:                     
 724:                 case USUAL_STRATEGY :
 725:                     if (beenRed > LONGESTLIGHTTIME)
 726:                     {
 727:                         return true;
 728:                     }
 729:                     if (!waiting(dir, scale))
 730:                     {
 731:                         return true;
 732:                     }
 733:                     break;
 734:                     
 735:                 case MAD_STRATEGY :
 736:                     if (!waiting(dir, scale))
 737:                     {
 738:                         return true;
 739:                     }
 740:                     if (anybodyMadder(dir))
 741:                     {
 742:                         return true;
 743:                     }
 744:                     break;
 745:             }
 746: 
 747:             return false;
 748:         }
 749:     }
 750:     
 751:     /**
 752:      * is anybody waiting at this light?
 753:      * waiting , not as they approach
 754:      */
 755:     private boolean waiting(int dir, double scale)
 756:     {
 757:         Iterator iter = cars.iterator();
 758:         while (iter.hasNext())
 759:         {
 760:             MyCar car = (MyCar) iter.next();
 761:             if (car.fromDirection == dir)
 762:             {
 763:                 if (car.position > 0 && car.position < 3 * streetsize / scale)
 764:                 {
 765:                     return true;
 766:                 }
 767:             }
 768:         }
 769:         return false;
 770:     }
 771:     
 772:     /**
 773:      * are other directions madder?
 774:      * madder means at least 10% madder, and plus 10
 775:      */
 776:     private boolean anybodyMadder(int dir)
 777:     {
 778:         for (int i = 0; i < DIRECTIONS; i++)
 779:         {
 780:             if (i != dir)
 781:             {
 782:                 if (madness[i] > 1.1 * madness[dir] + 10)
 783:                 {
 784:                     return true;
 785:                 }                
 786:             }
 787:         }
 788:         return false;
 789:     }
 790:        
 791:     /**
 792:      * starting point, if not an applet
 793:      */
 794:     public static void main(String[] args)
 795:     {
 796:         JFrame frame = new JFrame("Stop");
 797:         
 798:         // Size and position it nicely
 799:         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
 800:         int h = screen.height/10;
 801:         int w = screen.width/10;
 802:         frame.setSize(8*w, 8*h);
 803:         frame.setLocation(w, h);
 804: 
 805:         // Handle the little X in the window corner nicely
 806:         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 807: 
 808:         Stop stop = new Stop();
 809:         frame.getContentPane().add(stop.initialize());
 810:         
 811:         frame.show();
 812:         
 813:         stop.startClock(4 * w, 4 * h);
 814:     }
 815: }

stop.html - applet

   1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2: <html xmlns="http://www.w3.org/1999/xhtml">
   3: <head>
   4:   <title>Road Rage Traffic Simulation Applet</title>
   5: </head>
   6: <body>
   7: <h3>Road Rage Traffic Simulation Applet</h3>
   8: 
   9: <table border="2"><tr><td>
  10: 
  11: <applet archive="Stop.jar" code="Stop" width="1000" height="650">
  12:     Your browser is completely ignoring the &lt;APPLET&gt; tag!
  13: </applet>
  14: 
  15: </td></tr></table>
  16: 
  17: <p>
  18:     If this didn't work, you probably have JRE 1.1 in a Microsoft browser. To run a Swing
  19:     applet, you should install JRE 1.3 or later, which is available through this link:
  20:     <a href="http://java.sun.com/products/plugin/">http://java.sun.com/products/plugin/</a>
  21: </p>
  22: 
  23: <p>There is a somewhat similar application <a href="http://xn--mhlemann-65a.ch/highwaysim/">here</a>.</p>
  24: 
  25: </body>
  26: </html>
  27: 
Email: steve@oharasteve.com