Download:
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;
}
/***************************************************************************/
This does not compile without chilb105 routines.
Maintained by John Loomis, updated Wed Feb 21 17:13:39 2007