Bank Simulation

Download:

bank.zip (bank simulation)
chilb105.zip (book files)

Here is Horstman's code. However - STL elements copy objects (not pointers to objects) so polymorphism does not work here. Code such as event_queue.cpp looks at the amount of copying going on.

bank1.cpp


/****************************************************************************
** COPYRIGHT (C):    1994 Cay S. Horstmann. All Rights Reserved.
** PROJECT:          Mastering Object-Oriented Design
** FILE:             bank1.cpp
** PURPOSE:          A bank simulation
** VERSION           1.0
** LANGUAGE:         Borland C++ 3.0
** TARGET:           IBM PC
** PROGRAMMER:       Cay Horstmann (CSH)
** START DATE:       4-30-92 (CSH)
** UPDATE HISTORY:
****************************************************************************/

/* IMPORT ******************************************************************/

#include <math.h>
#include "chiarray.h"
#include "chiqueue.h"
#include "chiprioq.h"

/* TYPES *******************************************************************/

typedef double Time; // measured in minutes

/*-------------------------------------------------------------------------*/

class Event
/* PURPOSE:    An event that is scheduled for execution at some time
*/
{
public:
   Event(Time t);

   virtual void process() = 0;
   Time time() const;
   virtual ~Event() {}
private:
   Time _time;
};

/*-------------------------------------------------------------------------*/

class Arrival : public Event
/* PURPOSE:    Customer arrives at bank
*/
{
public:
   Arrival(Time);
   virtual void process();
};

/*-------------------------------------------------------------------------*/

class Departure : public Event
/* PURPOSE:    Customer departs from teller
*/
{
public:
   Departure(Time, int teller);
   virtual void process();
private:
   int _teller;
};

/*-------------------------------------------------------------------------*/

class Customer
/* PURPOSE:    A bank customer
*/
{
public:
   Customer(Time t);
   Time arrival_time() const;
private:
   Time _arrival_time;
};

/*-------------------------------------------------------------------------*/

class BankStatistics
/* PURPOSE:    Gather statistics to compute averages
*/
{
public:
   BankStatistics();
   void add(Time t);
   void print() const;
   double average_time() const;
private:
   int _ncust;
   Time _total_time;
};

/*-------------------------------------------------------------------------*/

class Bank
/* PURPOSE:    Simulation of customer traffic in a bank
*/
{
public:
   Bank();
   void add(Customer*);
   void add_to_teller(int teller, Customer*);
   Customer* remove(int teller);
   void print() const;
private:
   enum { NTELLER = 5 };
   Chi_PtrArray<Customer> _teller;
   Chi_Queue<Customer*> _cust_queue;
};

/* GLOBALS *****************************************************************/

const Time INTERARRIVAL = 1.0; // 1 minute
const Time AVG_PROCTIME = 5.0; // 5 minutes

static int event_compare(const Event* a, const Event* b);

Chi_PtrPriorityQueue<Event> event_queue(event_compare);
Time now;
Bank bank;
BankStatistics stat;

/* FUNCTIONS ***************************************************************/

static double expdist(double mean)
/* PURPOSE:    Compute exponentially distributed random numbers
   RECEIVES:   mean - the mean of the number sequence
   RETURNS:    a random number
*/
{  double r = rand();
   r /= RAND_MAX;
   return -mean*log(r);
}

/*.........................................................................*/

static int event_compare(const Event* a, const Event* b)
/* PURPOSE:    compare two events by their time stamp
   RECEIVES:   a, b - pointers to two events
   RETURNS:    -1 if a is scheduled earlier than b, 0 if they are
               scheduled at the same time, 1 otherwise
*/
{  Time d = a->time() - b->time();
   return (d > 0) - (d < 0);
}

/*.........................................................................*/

void main()
{  const Time STARTTIME = 9 * 60; // 9 a.m.
   const Time ENDTIME = 17 * 60; // 5 p.m.

   now = STARTTIME;

   event_queue.insert(new Arrival(now));

   while (event_queue.length() > 0 && now <= ENDTIME)
   {  Event* event = event_queue.remove();
      now = event->time();
      event->process();
      delete event;
      bank.print();
   }

   stat.print();
}

/*-------------------------------------------------------------------------*/

Event::Event(Time t)
/* RECEIVES:   t - the execution time of this event
*/
: _time(t)
{}

/*.........................................................................*/

Time Event::time() const
/* RETURNS:    the time at which the event is to be executed
*/
{  return _time;
}

/*-------------------------------------------------------------------------*/

Arrival::Arrival(Time t)
/* RECEIVES:   t - the time at which the arrival will occur
*/
: Event(t)
{}

/*.........................................................................*/

void Arrival::process()
/* PURPOSE:    process an arrival event
*/
{  Customer* c = new Customer(now);
   bank.add(c);
   Time t = expdist(INTERARRIVAL);
   event_queue.insert(new Arrival(now + t));
}

/*-------------------------------------------------------------------------*/

Departure::Departure(Time t, int teller)
/* RECEIVES:   t - the time at which the departure will occur
               teller - teller position
*/
: Event(t), _teller(teller)
{}

/*.........................................................................*/

void Departure::process()
/* PURPOSE:    process a departure event
*/
{  Customer* c = bank.remove(_teller);
   delete c;
}

/*-------------------------------------------------------------------------*/

Customer::Customer(Time t)
/* RECEIVES:   the time at which the customer entered the bank
*/
: _arrival_time(t)
{}

/*.........................................................................*/

Time Customer::arrival_time() const
/* RETURNS:    the time at which the customer entered the bank
*/
{  return _arrival_time;
}

/*-------------------------------------------------------------------------*/

BankStatistics::BankStatistics()
: _ncust(0), _total_time(0)
{}

/*.........................................................................*/

void BankStatistics::add(Time t)
/* PURPOSE:    add another customer who is leaving the bank to the statistics
   RECEIVES:   t - the time the customer left
*/
{  _ncust++;
   _total_time += t;
}

/*.........................................................................*/

double BankStatistics::average_time() const
/* PURPOSE:    returns the average time the customers spent in the bank
*/
{  if (_ncust == 0) return 0;
   else return _total_time/_ncust;
}

/*.........................................................................*/

void BankStatistics::print() const
/* PURPOSE:    print a summary of the gathered statistics
*/
{  cout << _ncust
      << " customers. Average time "
      << average_time() << " minutes." << endl;
}

/*-------------------------------------------------------------------------*/

Bank::Bank() : _teller(1, NTELLER) {}

/*.........................................................................*/

void Bank::add(Customer* c)
/* PURPOSE:    Add a customer to the bank
   RECEIVES:   c - the customer
*/
{  for (int i = 1; i <= NTELLER; i++)
      if (_teller[i] == 0)
      {  add_to_teller(i, c);
         return;
      }
   _cust_queue.insert(c);
}

/*.........................................................................*/

void Bank::add_to_teller(int i, Customer* c)
/* PURPOSE:    add customer to an empty teller
   RECEIVES:   i - teller position
               c - the customer to add
*/
{  CHI_ASSERT_PRECOND(_teller[i] == 0);
   _teller[i] = c;
   Time t = expdist(AVG_PROCTIME);
   event_queue.insert(new Departure(now + t, i));
}

/*.........................................................................*/

Customer* Bank::remove(int i)
/* PURPOSE:    remove customer from teller
   RECEIVES:   i - teller position
*/
{  Customer* c = _teller[i];
   _teller[i] = 0;
   stat.add(now - c->arrival_time());
   if (_cust_queue.length() > 0)
      add_to_teller(i, _cust_queue.remove());
   return c;
}

/*.........................................................................*/

void Bank::print() const
/* PURPOSE:    Print teller and queue
*/
{  for (int i = 1; i <= NTELLER; i++)
      cout << (_teller[i] == 0 ? '.' : 'C');
   cout << '<';
   int q = _cust_queue.length();
   for (int j = 1; j <= q; j++) cout << 'C';
   cout << endl;
}

/***************************************************************************/


Results

This does not compile without chilb105 routines.


Maintained by John Loomis, updated Wed Feb 21 17:13:39 2007