Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

(In C++ language please)Write a simulation program of the lines at a grocery sto

ID: 3690882 • Letter: #

Question

(In C++ language please)Write a simulation program of the lines at a grocery store. The program will be similar to the car wash simulation, except that there are multiple queues instead of one. You might use a vector of queues to simulate the lines. Assume that there are five cashier lines at the grocery store. Customers enter randomly to check out, and then enter the shortest line. If the lines are equal, then the first available line is chosen. Each transaction takes a random amount of time to complete.

            For additional work, expand the grocery line program to allow shoppers to:

Avoid a line if al lines are a certain length

Leave a line if they have waited beyond a certain line

Check if another line is shorter at specified time intervals

Switch lines if another line is shorter

Explanation / Answer

Simulation.h

#pragma once

#include <iostream>
#include <ctime>

using namespace std;

#include "Customer.h"
#include "Timer.h"
#include "DynamicQueue.h"


const int NUM_CATEGORIES = 5;
class Simulation {

   public:

       //default constructor
       Simulation() {
          

           avgCustomerServiceTime = 0;
           avgCustomerWaitingTime = 0;
           avgCashierIdleTime = 0;
           totalServiceTime = 0;
           totalCustomerWaitingTime = 0;
           totalCashierIdleTime = 0;
           totalNumberOfCustomers = 0;
           customersRemaining = 0;

           servicePercent = new int[NUM_CATEGORIES];
           allCashiers = new dynamic_queue<Customer>[numCashiers];
          

           //get inputs for simulation
           cout << "Please enter the average arrival rate of customers in number per minute: " << endl;
           cin >> arrivalRate;

           cout << "Please enter the number of registers: " << endl;
           cin >> numCashiers;

           //create the correct number of cashiers
           for(int i = 0; i < numCashiers; i++) {
              
               allCashiers[i] = *new dynamic_queue<Customer>;
           }

           cout << "Please enter the length of time to run the simulation in minutes: " << endl;
           cin >> lengthOfSimulation;

           //cout << "Please enter the distribution of customer service times: " << endl;
           int percent = 0;
           int   sum = 0;
           for (int i = 0; i < NUM_CATEGORIES; i++) {

               //cout << " <= " << (i + 1) << " min. ";  
               //cin >> percent;
               //servicePercent[i] = percent;
               //sum += percent;
               //cout << "sum: " << sum << endl;
               servicePercent[i] = 20 + sum;
               sum += 20;
           }

           //check to make sure the inputs add up to 100
           while (sum != 100) {
              
               cout << "Invalid distribution. Must add up to 100 %" << endl;
               cout << "old sum was: " << sum << endl;
               sum = 0;
               for (int i = 0; i < NUM_CATEGORIES; i++) {
                  
                   cout << " <= " << i + 1 << " min. ";   cin >> percent;
                   servicePercent[i] = percent;
                   sum += percent;
                   cout << "sum: " << sum << endl;
               }
           }          

           //set the countdown timer
           myTimer.set(lengthOfSimulation);      

           //intialize random number generator
           long seed = long(time(0));
           srand(seed);
       }
       //destructor
       //deletes all dynamically created elements of allCashiers[]
       //deletes dynamically created member arrays
       ~Simulation() {

           for (int i = 0; i < numCashiers - 1; i++) {
          
               delete &allCashiers[i];
           }

           delete [] allCashiers;
           delete [] servicePercent;
       }
       //this function is the 'brains' of the simulation. It computes and processes customers and cashiers for the runtime specified.
       void run() {
          
           while (myTimer.timeRemaining() > 0) {

               //go through each cashier and run the service function which will check
               //if their customer is ready to check out and do so if able
               for (int i = 0; i < numCashiers; i++) {
                  
                   if (!allCashiers[i].isEmpty()) {
              
                       int busyTimeLeft = allCashiers[i].getHead().getServiceTime();
                      
                       service(busyTimeLeft, i);                  
                   }
                   else {

                       totalCashierIdleTime++;
                   }
               }              
               checkForNewCustomer();
               myTimer.tick();
           }

           cout << " Not accepting any more customers -- service remaining customers in line" << endl;
          
           for (int i = 0; i < numCashiers; i++) {

               while (!allCashiers[i].isEmpty()) {

                   int busyTimeLeft = allCashiers[i].getHead().getServiceTime();
                   service(busyTimeLeft, i);                  
               }
           }

           display(cout);
       }
       //function is passed the remaining service time of the customer in the front of the line
       // as well as the cashier the customer is in line for
       void service(int& busyTimeRemaining, int cashier) {
      
           if (busyTimeRemaining > 0) { //the head customer still has more service time to process

               busyTimeRemaining--;
               allCashiers[cashier].getHead().setServiceTime(busyTimeRemaining);

               //add waiting time of the customers in line to the total
               totalCustomerWaitingTime += allCashiers[cashier].getSize() - 1;

               return;
           }
           else {
               //check to see if this cashier are nonempty and if they are have each on
               if (!allCashiers[cashier].isEmpty()) { //there is a customer ready to check out

                   int arrivalTime = allCashiers[cashier].getHead().getArrivalTime();

                   allCashiers[cashier].dequeue();   //cash out head customer
                  
                   if (!allCashiers[cashier].isEmpty()) {

                       Customer nextCust = allCashiers[cashier].getHead();
                       busyTimeRemaining = nextCust.getServiceTime();
                   }

                   customersRemaining--;                  
               }
           }          
       }
       //This function checks for and adds customers to the smallest line of a cashier
       void checkForNewCustomer() {

           //activates new customer procedure for each arrival per minute. Case1: arrivalRate > 1
           for (int i = 0; i < arrivalRate; i++) {

               //a new customer is ready to get in line, create random service time
               int r = rand() % 100;
               int serviceTime = 0;
               int culmServiceTime = servicePercent[serviceTime];

               while (r > culmServiceTime) {

                   culmServiceTime += servicePercent[serviceTime];
                   serviceTime++;
               }

               totalServiceTime += serviceTime + 1;

               //create a new customer and add it to the smallest line at a cashier
               Customer newCust(myTimer, serviceTime + 1);
               totalNumberOfCustomers++;
               customersRemaining++;

               int min = 9999999;
               int smallestLine = 0;
               for (int i = 0; i < numCashiers; i++) {

                   if (allCashiers[i].getSize() < min) {

                       min = allCashiers[i].getSize();
                       smallestLine = i;
                   }
               }

               allCashiers[smallestLine].enqueue(newCust);
              
           }

           if (arrivalRate < 1) { //Case 2: arrivalRate < 1
              
               //random number between 0 and 99
               int x = rand() % 100;

               //calculates the probability that a customer has arrived
               if (x < 100 * arrivalRate) {

                   //a new customer is ready to get in line, create random service time
                   int r = rand() % 100;
                   int serviceTime = 0;
                   int culmServiceTime = servicePercent[serviceTime];

                   while (r > culmServiceTime) {

                       culmServiceTime += servicePercent[serviceTime];
                       serviceTime++;
                   }

                   totalServiceTime += serviceTime + 1;

                   //create a new customer and add it to the smallest line at a cashier
                   Customer newCust(myTimer, serviceTime + 1);
                   totalNumberOfCustomers++;
                   customersRemaining++;

                   int min = 9999999;
                   int smallestLine = 0;
                   for (int i = 0; i < numCashiers; i++) {

                       if (allCashiers[i].getSize() < min) {

                           min = allCashiers[i].getSize();
                           smallestLine = i;
                       }
                   }

                   allCashiers[smallestLine].enqueue(newCust);
               }          
           }
       }
       //Displays the average customer service and wait time as well as the average cashier idle time
       void display(ostream &out) {

           //cout << totalNumberOfCustomers;

           cout << " total number of customers :" << totalNumberOfCustomers << endl;

           cout << " totalservice time: " << totalServiceTime << endl;
           cout << " total customer waiting time: " << totalCustomerWaitingTime << endl;
           cout << " total cashier idle time: " << totalCashierIdleTime << endl;


           avgCustomerServiceTime = (double) totalServiceTime / totalNumberOfCustomers;
           avgCustomerWaitingTime = (double)totalCustomerWaitingTime / totalNumberOfCustomers;
           avgCashierIdleTime = (double)totalCashierIdleTime / numCashiers;


           cout << " The average customer service time was: " << avgCustomerServiceTime << " minutes";
           cout << " The average customer waiting time was: " << avgCustomerWaitingTime << " minutes";
           cout << " The average cashier idle time was: " << avgCashierIdleTime << " minutes";
       }
   private:

       //inputs
       int lengthOfSimulation;
       double arrivalRate;
       int * servicePercent;

       //tracking variables
       int totalServiceTime;
       int totalCustomerWaitingTime;
       int totalCashierIdleTime;
       int totalNumberOfCustomers;
       int customersRemaining;

       //outputs
       double avgCustomerServiceTime;
       double avgCustomerWaitingTime;
       double avgCashierIdleTime;

       //countdown timer
       Timer myTimer;

       //Number of cashiers, set at runtime
       int numCashiers;

       //array of queues that house customers
       dynamic_queue<Customer> * allCashiers;
};

Customer.h
#pragma once

#include <iostream>

#include "Timer.h"

using namespace std;

class Customer {

   public:

       //default constructor
       Customer(){
      
           timeOfArrival = serviceTime = 0;
       }
       //specificconstructor
       Customer(const Timer &T, int serviceTime) {

           //record the customer's time of arrival
           timeOfArrival = T.timeRemaining();

           //set the service time
           this->serviceTime = serviceTime;
       }
       //copy constructor
       Customer(const Customer &copyCust) {

           timeOfArrival = copyCust.timeOfArrival;
           serviceTime = copyCust.serviceTime;

       }
       //returns the arrival time
       int getArrivalTime() {

           return timeOfArrival;
       }
       //returns a reference to the serviceTime
       int& getServiceTime() {

           return serviceTime;
       }
       //sets the service time
       void setServiceTime(int time) {

           serviceTime = time;
       }
       //decreases the serviceTime by 1
       void decrementServicetime() {

           //return serviceTime - 1;
           serviceTime--;
       }
       //displays the object's variables
       void display(ostream &out) {

           out << "Arrival Time:   " << timeOfArrival << endl;
           out << "Service Time:   " << serviceTime << endl;
       }  
       //sets this object to the RHS one
       const Customer& operator=(const Customer &RHS) {

           if (this == &RHS) return *this;

           this->timeOfArrival = RHS.timeOfArrival;
           this->serviceTime = RHS.serviceTime;

           return *this;
       }
      
private:
       //member variables
       int timeOfArrival;
       int serviceTime;
      

};

DynamicQueue.h
#pragma once

#include <iostream>

using namespace std;


template <class QueueElement>
class dynamic_queue {

   public:

       //default constructor
       dynamic_queue(int capacity = 10) {

           itail = 0;
           ihead = 0;
           initial_capacity = 10;
           array_capacity = capacity;
           array_size = 0;
           myArray = new QueueElement[initial_capacity];
       }
       //copy constructor
       dynamic_queue(const dynamic_queue &copyQueue) {  
  
           array_capacity = copyQueue.array_capacity;
           array_size = copyQueue.array_size;

           myArray = new QueueElement[array_capacity];

           for (int i = 0; i < array_capacity; i++) {

               myArray[i] = copyQueue.myArray[i];
           }

           ihead = copyQueue.ihead;
           itail = copyQueue.itail;      
       }
       //default destructor
       ~dynamic_queue() {

           for (int i = 0; i < array_capacity; i++) {
          
               delete &myArray[i];
           }
  
           delete[] myArray;  
       }
       //returns a reference to the head element of the queue
       QueueElement& getHead() {

           if (array_size != 0) {

               return myArray[ihead % array_capacity];
           }
           else {

               throw new exception("Queue is Empty");
           }
       }
       //returns a reference to the tail element
       QueueElement& getTail() {
  
           if (array_size != 0) {

               return myArray[itail % array_capacity];
           }
           else {

               throw new exception("Queue is Empty");
           }
       }
       //method to return the size of the dynamic array
       int getSize() const {
  
           return array_size;
       }
       //returns a boolean staing whether the dynamic array is empty or not
       bool isEmpty() const {

           if (array_size == 0) {

               return true;
           }
           else {

               return false;
           }
       }
   //checks if queue is full
           bool isFull() {

               if (getSize() == array_capacity) return true;
               else return false;
           }
           /*-----------------------------------------------------------------------
           isFull

           Precondition: none
           Postcondition: returns a boolean value true if the queue is full, false otherwise
           -----------------------------------------------------------------------*/

           //creates a new array with double the capacity of the current array and copy each element into the new array
           void increaseSize() {

               QueueElement * newArray;
               newArray = new QueueElement[getCapacity() * 2];

               //copy each element of the old array
               int temp = ihead;
               for (int i = 0; i < getSize(); i++) {

                   newArray[i] = myArray[temp];
                   temp = (temp + 1) % array_capacity;
               }

               //program works with the delete commented out as well as only inutting arrival rate < #registers
               //delete[] myArray;

               //point myArray variable to the newly created array
               myArray = newArray;

               delete[] newArray;

               array_capacity *= 2;
               ihead = 0;
               itail = array_size - 1;
           }
           /*-----------------------------------------------------------------------
           increase size

           Precondition: queue is full
           Postcondition: doubles the capacity of the current array as a new array and copies all of its elements to a new array
           -----------------------------------------------------------------------*/

           //creates a new array with half the capacity of the current array and copy each element into the new array
           void decreaseSize() {

               initial_capacity = 10;
               //cannot reduce the capacity of the array to below the intial capacity
               if ((array_capacity / 2) < initial_capacity) {

                   return;
               }

               QueueElement * newArray;
               newArray = new QueueElement[array_capacity / 2];

               //copy each element of the old array

               int temp = ihead;
               for (int i = 0; i < getSize(); i++) {

                   cout << "size of current array: " << getSize() << endl;
                   cout << "i" << i << endl;

                   newArray[i] = myArray[temp];
                   temp = (temp + 1) % array_capacity;
               }

               //program works with the delete commented out as well as only inutting arrival rate < #registers
               //delete[] myArray;

               //point myArray variable to the newly created array
               myArray = newArray;

               delete[] newArray;

               array_capacity /= 2;
               ihead = 0;
               itail = array_size - 1;
           }
           /*-----------------------------------------------------------------------
           decreaseSize

           Precondition: array is equal or less than 1/4 full
           Postcondition: copies all of the array elements into a new array of 1/2 the capacity
           -----------------------------------------------------------------------*/


           //returns the capacity of the dynamic array as an int
           int getCapacity() {

               return array_capacity;
           }
           /*-----------------------------------------------------------------------
           getCapacity

           Precondition: none
           Postcondition: returns an int of the array's capacity
           -----------------------------------------------------------------------*/

           //displays each 'active' element of the array (i.e. ignores elements that are actually in the array, but are not in the queue)
           void display(ostream &out) const {

               cout << endl << "The current contents of the list are: " << endl << endl;

               if (array_size == 0) {

                   cout << "Queue is empty" << endl;
                   return;
               }

               for (int i = 0; i < getSize(); i++) {

                   cout << myArray[(i + ihead) % array_capacity] << endl;
               }              
           }
           /*-----------------------------------------------------------------------
           display

           Precondition: the stream to print to
           Postcondition: displays all the elements of the queue
           -----------------------------------------------------------------------*/  

           //increments the head tracker to 'remove' the oldest queue element
           void dequeue() {

               if (isEmpty()) {

                   throw new exception("Queue is empty");
               }


               ihead = (ihead + 1) % array_capacity;

               array_size--;

               //make sure the size of the array can never be less than 0
               if (array_size <= 0) array_size = 0;

               if (getSize() <= (.25 * array_capacity)) {

                   decreaseSize();
               }
           }
           /*-----------------------------------------------------------------------
           Default Constructor

           Precondition: none
           Postcondition: increments the head tracker, essentially 'removing' the head element
           -----------------------------------------------------------------------*/

           //adds a new element at the tail of the queue
           void enqueue(const QueueElement &value) {

               if (isFull() != true) {

                   if (isEmpty() == true) {

                       myArray[itail] = value;
                   }
                   else {

                       itail = (itail + 1) % array_capacity;
                       myArray[itail] = value;
                   }

                   array_size++;
               }
               else {

                   increaseSize();
                   enqueue(value);
               }
           }
           /*-----------------------------------------------------------------------
           enqueue

           Precondition: the element to be added to the array
           Postcondition: A element of any type is added to the tail of the array
           -----------------------------------------------------------------------*/

           //switches all the member variables of a to b and vice versa
           bool swap(dynamic_queue &a, dynamic_queue &b) {

               if (a.myArray != b.myArray) {

                   dynamic_queue<QueueElement> temp;

                   temp = a;
                   a = b;
                   b = temp;

                   return true;
               }
               else {

                   return false;
               }
           }
           /*-----------------------------------------------------------------------
           swap

           Precondition: a dynamic_queue
           Postcondition: A swaps all the variables of the passed in queue with the local queue
           -----------------------------------------------------------------------*/

           //Empties the queue and resizes it to the intial capacity
           void clear() {

               delete[] myArray;

               QueueElement * newArray;
               newArray = new QueueElement[initial_capacity];

               myArray = newArray;
               array_size = 0;
               itail = 0;
               ihead = 0;
           }
           /*-----------------------------------------------------------------------
           clear

           Precondition: none
           Postcondition: resets all the elements of the queue and intializes it back to its intial capacity
           -----------------------------------------------------------------------*/

           //assigns the right queue's contents to the left queue
           const dynamic_queue& operator=(const dynamic_queue &RHS) {

               if (this->myArray == RHS.myArray) return *this;

               array_capacity = RHS.array_capacity;
               array_size = RHS.array_size;

               myArray = new QueueElement[array_capacity];

               for (int i = 0; i < array_capacity; i++) {

                   myArray[i] = RHS.myArray[i];
               }

               ihead = RHS.ihead;
               itail = RHS.itail;

               return *this;
           }
           /*-----------------------------------------------------------------------
           operator =

           Precondition: a dynamic_queue
           Postcondition: the LHS queue now has all the variables and queue elements of the HRS queue
           -----------------------------------------------------------------------*/

           friend ostream& operator<< <> (ostream&, const dynamic_queue<dynamic_queue>&) {}

private:
   /***** Data Members *****/
   int ihead;
   int   itail;
   int initial_capacity; // initial capacity of array
   int array_capacity; // current capacity of the array
   int array_size; // current size of queue stored in array
   QueueElement *myArray; // pointer to dynamically allocated array
};

Timer.h

#pragma once

#include <cassert>
using namespace std;


class Timer {

   public:

       //default constructor
       Timer(int initTime = 0) {

           assert(initTime >= 0);
           minutes = initTime;
       }

       //sets minutes to the passed value
       void set(int minutes) {

           assert(minutes >= 0);
           this->minutes = minutes;
       }

       //'advances' one minute of time
       void tick() {

           minutes--;
       }

       //returns the number of minutes remaining in the simulation
       int timeRemaining() const {

           return minutes;
       }


   private:

       int minutes;

};

main.cpp

#pragma once
#include "Timer.h"
#include "Customer.h"
#include "Simulation.h"

#include <iostream>

using namespace std;

void runSim() {

   //run the simulation
   Simulation sim;
   sim.run();

   cin.ignore();
   cin.ignore();
   cin.ignore();

   exit(0);
}

void runQueueTest() {

   //test dynamic queue class
   dynamic_queue<int> queue1;
   queue1.enqueue(1);
   queue1.enqueue(2);
   queue1.enqueue(3);
   queue1.enqueue(4);
   queue1.enqueue(5);
   queue1.enqueue(6);
   queue1.enqueue(7);

   queue1.dequeue();
   queue1.dequeue();
   queue1.dequeue();

   queue1.enqueue(8);
   queue1.enqueue(9);
   queue1.enqueue(10);

   cout << "queue should have the elements: 4 5 6 7 8 9 10" << endl;
   queue1.display(cout);

   queue1.dequeue();
   queue1.dequeue();
   queue1.dequeue();
   queue1.dequeue();
   queue1.dequeue();
   queue1.dequeue();
   queue1.dequeue();

   cout << " queue should now be empty " << endl;
   queue1.display(cout);

   queue1.clear();

   cout << " adding some more elements" << endl;
   queue1.enqueue(1);
   queue1.enqueue(2);
   queue1.enqueue(3);

   cout << " queue should have the elements: 1 2 3" << endl;
   queue1.display(cout);

   cout << "head and tail: " << queue1.getHead() << " " << queue1.getTail() << endl;
   cin.ignore();
   cin.ignore();
   cin.ignore();
   exit(0);
}

int main() {

   int input = 0;
   cout << "Would you like to test the dynamic queue or run the grocery store simulation? (1 for queue, 2 for simulation)" << endl;
   cin >> input;

   if (input == 1) {

       runQueueTest();
   }
   if (input == 2) {

       runSim();
   }  

   return 0;
}