import java.util.List; import java.util.LinkedList; import java.util.Arrays; // only for debugging purposes /* An instance of this class can carry out a discrete event simulation that ** models a scenario in which people seeking service (i.e., "customers") ** arrive, wait in a queue for an available "clerk", and then are provided ** service by such a clerk. Of interest is how long customers wait in the ** queue until they are served, which is a function of several factors, ** including how frequently customers arrive, how long it takes to service ** them, and how many clerks are present to provide service. ** ** Author: R. McCloskey, March 2026 ** Adapted from a similar Java class in "Object-Oriented Data Structures ** using Java" (4th edition; by Dale, Joyce, and Weems; published by ** Pearson). An important difference is that here there is only one ** queue, but (possibly) multiple clerks, whereas in Dale's, et. al. ** version there are multiple queues and each arriving customer is ** placed into a queue of minimum length. Here, all customers wait in ** the same queue and are "sent to" a clerk whenever one becomes free ** (having completed giving service to an earlier-arriving customer). ** Student Author: < Your name > ** Collaborators: ... ** Known defects: ... */ public class Simulation { // instance variables // ------------------ protected int closingTime; // time at which no new arrivals are allowed protected int numClerks; // # of clerks to provide service protected int numBusyClerks; // # clerks currently serving customers protected QueueViaLink1 customersWaiting; // customers waiting protected List customersBeingServed; // customers being served protected List customersFinished; // already-served customers protected CustomerGenerator custGen; // to "generate" customers protected int currentTime; protected Customer nextCustomer; protected int nextArrivalTime; protected int nextFinishTime; // Class invariants: // ----------------- // customersWaiting: queue of customers waiting to be served, in // ascending order by arrival time // customersBeingServed: list containing the customers currently being // served, in ascending order by finish time. The size/length of this // list cannot exceed 'numClerks'. // numBusyClerks: equal to customersBeingServed.size() (and hence this is // an unnecessary "convenience" variable) // customersFinished: list of customers who have already received // service, in ascending order by finish time. // currentTime: time at which the most recent arrival or departure of // a customer occurred (but zero initially) // nextCustomer: next customer destined to arrive // nextArrivalTime: arrival time of that next customer (which is equal to // nextCustomer.arrivalTime(), which makes this a convenience variable) // nextFinishTime: minimum among finish times of customers currently // receiving service, or Integer.MAX_VALUE if there are no such customers. // constructor // ----------- /* Establishes the object to be used in generating new customers. */ public Simulation(CustomerGenerator custGen) { this.custGen = custGen; } // observers // --------- /* Returns the "closing time" of the most recent simulation, ** meaning the maximum allowed arrival time, plus 1. ** pre: a call to simulate() has occurred */ public int closingTime() { return closingTime; } /* Returns the number of units of time that elapsed in the most recent ** simulation, up to the time at which the last customer departed. ** pre: a call to simulate() has occurred */ public int duration() { return currentTime; } /* Returns the number of clerks that were employed in the most ** recent simulation. ** pre: a call to simulate() has occurred */ public int numberOfClerks() { return numClerks; } /* Returns a list of all customers who were provided service during ** the most recent simulation, in ascending order by finishing time. ** pre: a call to simulate() has occurred */ public List customers() { return customersFinished; } // to carry out a simultion // ------------------------ /* Carries out a simulation with the specified "closing time" in which ** the indicated number of clerks is available to provide service to ** customers. Only customers who arrive before closing time get service. */ public void simulate(int closingTime, int numClerks) { this.closingTime = closingTime; this.numClerks = numClerks; numBusyClerks = 0; customersWaiting = new QueueViaLink1(); customersBeingServed = new LinkedList(); customersFinished = new LinkedList(); currentTime = 0; // # units of time to have passed nextCustomer = custGen.nextCustomer(); nextArrivalTime = nextCustomer.arrivalTime(); nextFinishTime = Integer.MAX_VALUE; boolean keepGoing = true; while (keepGoing) { System.out.println("---------------------------------------"); System.out.println("Current time: " + currentTime); System.out.println("Next Arrival time: " + nextArrivalTime); System.out.println("Next Finish time: " + nextFinishTime); System.out.println("\nCustomers waiting:"); System.out.println(customersWaiting); System.out.println("\n# busy clerks: " + numBusyClerks); System.out.println("Customers being served:"); System.out.println(customersBeingServed); System.out.println("\nAction taken:"); if (!customersWaiting.isEmpty() && numBusyClerks < numClerks) { // If there is a customer waiting in the queue and at least one free // clerk, send the customer at the front of the queue to a clerk. fromQueueToService(); } else if (nextArrivalTime < Math.min(nextFinishTime, closingTime)) { // If the next customer's arrival time precedes both closing time // and the finish time of every customer receiving service, // place that next customer into the queue. fromArrivalToQueue(); } else if (numBusyClerks != 0) { // If execution reaches this point and at least one clerk is busy, // it must be that the finish time of the next customer to finish // is no later than the next customer's arrival time (or else // closing time has been reached, in which case no new customers // are allowed to arrive). The appropriate action is thus to // transfer the next-finishing customer to the list of finished // customers. fromServiceToFinished(); } else { // It must be that all customers are finished receiving service. keepGoing = false; } } } /* Makes all necessary adjustments to instance variables to effect the ** arrival of the next customer, including placing them into the queue. */ private void fromArrivalToQueue() { // STUB! } /* Makes all necessary adjustments to instance variables to effect a ** transfer of the customer at the front of the queue to the list of ** customers being served. ** pre: numBusyClerks < numClerks */ private void fromQueueToService() { // STUB! } /* Inserts the given customer into its proper place within the list ** of customers being served, so as to preserve that list being in ** ascending order by finish time. ** pre: numBusyClerks < numClerks */ private void insertIntoBeingServed(Customer c) { // STUB! } /* Makes all necessary adjustments to instance variables to effect ** the transfer of the customer with the minimum finish time among ** those being served into the list of finished customers. */ private void fromServiceToFinished() { // STUB! } }