Brugwachter

In het 2e jaar van Bedrijfskunde moest er bij het vak “Kwantitatieve Besluitvormingstechnieken” een programmeer opdracht gedaan worden. Het ging daarbij een wachtrij probleem waarvoor een optimale oplossing gevonden moest worden mbv een computer programma: “zoek gegeven een bepaalde aankomst verdeling van oost/west-bootjes en noord/zuid-autootjes naar de beste brugopening regel voor een brugwachter”, “hoeveel meter extra kade moet er komen bij een bepaalde toename van vrachtboten”, etc.

Het is 1984 en dat programma schrijf ik in de object oriented (!) taal “Simula” op de Vax computer van de RUG! Hoe cool is dat? In dat jaar waren er overigens maar 4 mede studenten die zo’n programma konden schrijven en uiteindelijk hebben wij dus alle opdrachten gemaakt. Niet verder vertellen! We hadden overigens geen onderlinge afspraken gemaakt, dus het zal niet heel moeilijk geweest zijn te herkennen welke programmeur welke programma geschreven had.

2024: … en toen kwam..

Je voert in: “schrijf een simula programma waarmee ik openingstijden voor een brug kan simuleren met autos uit nood en zuid richting en bootjes uit oost en west richting (beide met normaal verdeling). bij welk aantal bootjes moet de brug open? bereken de gemiddelde wachttijd van de auto en boot rijen”

Het resultaat is rond uit verbluffend:

BEGIN
  CLASS Bridge;
    BOOLEAN is_open;
  BEGIN
    PROCEDURE open_bridge;
    BEGIN
      is_open := TRUE;
      OutText("De brug is nu open voor bootjes."); OutImage;
    END open_bridge;

    PROCEDURE close_bridge;
    BEGIN
      is_open := FALSE;
      OutText("De brug is nu gesloten voor auto's."); OutImage;
    END close_bridge;

    is_open := FALSE;
  END Bridge;

  CLASS Traffic(DIRECTION, TYPE);
    TEXT DIRECTION, TYPE;
    REAL arrival_time;
  BEGIN
    PROCEDURE print_traffic;
    BEGIN
      OutText(TYPE); OutText(" uit "); OutText(DIRECTION); OutImage;
    END print_traffic;
  END Traffic;

  CLASS Queue;
    REF(Traffic) head, tail;
  BEGIN
    PROCEDURE enqueue(Traffic t);
    BEGIN
      IF head = NONE THEN
        head := t;
      ELSE
        tail.next := t;
      tail := t;
    END enqueue;

    PROCEDURE dequeue;
    REF(Traffic) t;
    BEGIN
      IF head /= NONE THEN
        t := head;
        head := head.next;
        RETURN t;
      ELSE
        RETURN NONE;
    END dequeue;

    PROCEDURE size;
    INTEGER count;
    REF(Traffic) current;
    BEGIN
      count := 0;
      current := head;
      WHILE current /= NONE DO
      BEGIN
        count := count + 1;
        current := current.next;
      END;
      RETURN count;
    END size;
  END Queue;

  REF(Bridge) bridge;
  REF(Queue) car_queue_north, car_queue_south, boat_queue;
  INTEGER i, boat_count, threshold, total_car_wait_time, total_boat_wait_time, car_count, boat_count_passed;
  REAL current_time, mean, stddev;
  TEXT directions[4], traffic_types[2];
  REF(Traffic) traffic;

  directions[1] := "noord"; directions[2] := "zuid"; directions[3] := "oost"; directions[4] := "west";
  traffic_types[1] := "auto"; traffic_types[2] := "bootje";

  bridge :- NEW Bridge;
  car_queue_north :- NEW Queue;
  car_queue_south :- NEW Queue;
  boat_queue :- NEW Queue;
  boat_count := 0;
  threshold := 3;  "Aantal bootjes waarna de brug opent"
  total_car_wait_time := 0;
  total_boat_wait_time := 0;
  car_count := 0;
  boat_count_passed := 0;
  current_time := 0.0;
  mean := 5.0;  "Gemiddelde aankomsttijd"
  stddev := 1.0;  "Standaarddeviatie"

  FOR i := 1 STEP 1 UNTIL 20 DO
  BEGIN
    current_time := current_time + Normal(mean, stddev);
    traffic :- NEW Traffic(directions[Random(1, 4)], traffic_types[Random(1, 2)]);
    traffic.arrival_time := current_time;
    traffic.print_traffic;

    IF traffic.TYPE = "bootje" THEN
    BEGIN
      boat_queue.enqueue(traffic);
      boat_count := boat_count + 1;
      IF boat_count >= threshold THEN
      BEGIN
        bridge.open_bridge;
        boat_count := 0;
        WHILE boat_queue.size > 0 DO
        BEGIN
          REF(Traffic) boat := boat_queue.dequeue;
          total_boat_wait_time := total_boat_wait_time + (current_time - boat.arrival_time);
          boat_count_passed := boat_count_passed + 1;
          OutText("Een bootje passeert."); OutImage;
          (Delay 2);
        END;
        bridge.close_bridge;
      END;
    END
    ELSE
    BEGIN
      IF bridge.is_open THEN
      BEGIN
        IF traffic.DIRECTION = "noord" THEN
          car_queue_north.enqueue(traffic);
        ELSE
          car_queue_south.enqueue(traffic);
        OutText("Een auto wacht in de rij."); OutImage;
      END
      ELSE
      BEGIN
        total_car_wait_time := total_car_wait_time + (current_time - traffic.arrival_time);
        car_count := car_count + 1;
        OutText("Een auto passeert."); OutImage;
        (Delay 1);
      END;
    END;

    OutText("Wachtrij noord: "); OutInt(car_queue_north.size, 0); OutText(" auto's"); OutImage;
    OutText("Wachtrij zuid: "); OutInt(car_queue_south.size, 0); OutText(" auto's"); OutImage;
    OutText("Wachtrij bootjes: "); OutInt(boat_queue.size, 0); OutText(" bootjes"); OutImage;
  END;

  OutText("Gemiddelde wachttijd auto's: "); OutReal(total_car_wait_time / car_count, 6, 2); OutText(" seconden"); OutImage;
  OutText("Gemiddelde wachttijd bootjes: "); OutReal(total_boat_wait_time / boat_count_passed, 6, 2); OutText(" seconden"); OutImage;
END;