public class BankSimulation
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: }