Source of BankSimulation.java


  1: import java.util.ArrayDeque;
  2: import java.util.Scanner;
  3: import java.util.PriorityQueue;
  4: import java.util.Queue;

  6: /**
  7:  * Simulate a day at the bank. Show statistics on how long people waited (on
  8:  * average and maximum), how many people got served, and such like.
  9:  */
 10: public class BankSimulation {

 12:     private static final Scanner kbd = new Scanner(System.in);
 13:     private static final int MAX_ARRIVAL_SEP = 6;
 14:     private static final int MIN_ARRIVAL_SEP = 0;
 15:     private static final int MIN_SERVICE_TIME = 2;
 16:     private static final int MAX_SERVICE_TIME = 8;
 17:     private static final int END_TIME = 60;

 19:     // state for this simulation
 20:     private static int time = 0;
 21:     private static int numTellersFree = 2;
 22:     private static int numCustomersServed = 0;
 23:     private static int totalWaitTime = 0;
 24:     private static int maxWaitTime = 0;

 26:     /**
 27:      * Run the simulation.
 28:      *
 29:      * @param args command line arguments ignored!
 30:      */
 31:     public static void main(String[] args) {
 32:         // create the event PQ and the customer waiting queue
 33:         PriorityQueue<Event> pq = new PriorityQueue<>();
 34:         Queue<Event> waiting = new ArrayDeque<>();

 36:         // run the simulation
 37:         addStartEvents(pq);
 38:         while (!pq.isEmpty()) {
 39:             Event e = pq.remove();
 40:             processEvent(e, pq, waiting);
 41:         }

 43:         // report the results
 44:         reportResults();
 45:     }

 47:     /**
 48:      * Add randomly generated arrival events to the given queue.
 49:      *
 50:      * @param pq the event queue to add events to.
 51:      */
 52:     private static void addStartEvents(PriorityQueue<Event> pq) {
 53:         // add arrivals every MIN_ARRIVAL_SEP to MAX_ARRIVAL_SEP minutes for an
 54:         // hour
 55:         int scheduled = randomInRange(MIN_ARRIVAL_SEP, MAX_ARRIVAL_SEP);
 56:         while (scheduled < END_TIME) {
 57:             pq.add(new Event(scheduled, "Arrival"));
 58:             scheduled += randomInRange(MIN_ARRIVAL_SEP, MAX_ARRIVAL_SEP);
 59:         }
 60:     }

 62:     /**
 63:      * Process an event, possibly updating the event queue and waiting list.
 64:      *
 65:      * @param   e   current event
 66:      * @param   pq  queue of events pending
 67:      * @param   waiting list of people waiting for service
 68:      */
 69:     private static void processEvent(Event e,
 70:                                     PriorityQueue<Event> pq,
 71:                                     Queue<Event> waiting) {
 72:         // trace
 73:         System.out.println(e.NAME + " @ " + e.TIME + " minutes.");

 75:         time = e.TIME;
 76:         if ("Arrival".equals(e.NAME)) {
 77:             // if there's a teller free
 78:             if (numTellersFree > 0) {
 79:                 // assign this client to that teller immediately
 80:                 --numTellersFree;
 81:                 // generate departure time and add to pq
 82:                 scheduleDeparture(pq, time);
 83:             }
 84:             // otherwise
 85:             else {
 86:                 // add this client to the wait queue
 87:                 waiting.add(e);
 88:             }
 89:         } else {
 90:             // it's a departure
 91:             // note one more customer served
 92:             ++numCustomersServed;
 93:             // if there's no one waiting
 94:             if (waiting.isEmpty()) {
 95:                 // one more teller is now free
 96:                 ++numTellersFree;
 97:             }
 98:             // otherwise serve the next customer in line
 99:             else {
100:                 // remove them from the queue
101:                 Event customer = waiting.remove();
102:                 // update total waiting time and max waiting time
103:                 int waited = time - customer.TIME;
104:                 totalWaitTime += waited;
105:                 if (waited > maxWaitTime) {
106:                     maxWaitTime = waited;
107:                 }
108:                 // generate departure time and add to pq
109:                 scheduleDeparture(pq, time);
110:             }
111:         }

113:         showState(waiting);
114:     }

116:     /**
117:      * Schedule the departure of a client.
118:      *
119:      * @param pq    the event queue
120:      * @param time  time client started being served
121:      */
122:     private static void scheduleDeparture(PriorityQueue<Event> pq, int time) {
123:         int duration = randomInRange(MIN_SERVICE_TIME, MAX_SERVICE_TIME);
124:         pq.add(new Event(time+duration, "Departure"));
125:     }

127:     /**
128:      * Generate a random number between LO and HI.
129:      *
130:      * @param LO smallest possible value
131:      * @param HI largest possible value
132:      * @return a random value in rand [LO, HI]
133:      */
134:     private static int randomInRange(int LO, int HI) {
135:         int range = HI - LO + 1;
136:         return (int)(LO + Math.random() * range);
137:     }

139:     /**
140:      * Show what's going on at this moment in the simulation.
141:      *
142:      * @param waiting the customers waiting in line.
143:      */
144:     private static void showState(Queue<Event> waiting) {
145:         System.out.printf("\n"
146:             + "Time: %2d\n"
147:             + "Number of people waiting: %3d\n"
148:             + "Number of tellers free:   %3d\n"
149:             + "Customers served:         %3d\n"
150:             + "Total waiting time:       %3d\n"
151:             + "Maximum waiting time:     %3d\n",
152:                 time, waiting.size(), numTellersFree, numCustomersServed,
153:                 totalWaitTime, maxWaitTime);
154:         pause();
155:     }

157:     /**
158:      * Report the results of the simulation.
159:      */
160:     private static void reportResults() {
161:         double aveWait = (double)totalWaitTime / (double)numCustomersServed;

163:         System.out.printf("\n"
164:             + "Time last customer left:  %3d\n"
165:             + "Customers served:         %3d\n"
166:             + "Maximum waiting time:     %3d\n"
167:             + "Average waiting time:     %6.2f\n",
168:                 time, numCustomersServed,
169:                 maxWaitTime, aveWait);
170:         pause();
171:     }

173:     /**
174:      * Wait for user to press enter key.
175:      */
176:     private static void pause() {
177:         System.out.print("\nPress enter...");
178:         kbd.nextLine();
179:         System.out.println();
180:     }

182: }