// world.cc: "model of the world" for CSC 270 simulation example
// -- J. Clarke, March-June 1996
//
// The first C++ version of this example attached these activities to
// the classes defining the objects taking the actions: the car class
// decided how much gas was needed, the arrival class decided when the
// next arrival would take place, etc. That approach required the
// random-number streams to be global variables; on the other hand,
// it did not require global functions as this one does.
//
// The change back to this design, with a module grouping the random
// processes together, was partly caused by dislike of the global variables,
// and partly by a recognition that the representation of the "world"
// needed to be kept together as much as the representation of the
// aspects of objects like cars, arrivals, etc.

#include <math.h>

#include "random.h"
#include "world.h"

// The random-number streams
static randStream * arrivalStream; // auto arrival times
static randStream * litreStream; // number of litres needed
static randStream * balkingStream; // balking probability
static randStream * serviceStream; // service times

// Initialize the random-number streams: read a seed for each
// and use it allocate a new stream.

void worldsetup (FILE *fin, FILE *fout)
{
	fprintf (fout, "and the following random number seeds:\n");
	unsigned short seed;
	fscanf (fin, "%hu", &seed);
	fprintf (fout, "         %hu", seed);
	arrivalStream = new randStream (seed);
	fscanf (fin, "%hu", &seed);
	fprintf (fout, "         %hu", seed);
	litreStream = new randStream (seed);
	fscanf (fin, "%hu", &seed);
	fprintf (fout, "         %hu", seed);
	balkingStream = new randStream (seed);
	fscanf (fin, "%hu", &seed);
	fprintf (fout, "         %hu", seed);
	serviceStream = new randStream (seed);
	fputc ('\n', fout);
}

// The interarrival time of the next car is exponentially distributed.

double interarrivalTime (void)
{
	const int MEAN = 50;
	// seconds, because r is a rate in 1/sec, and this is 1/r
	return - MEAN * log (arrivalStream -> nextfloat());
}

// The number of litres required by a car is uniform between 10 and 60.

double numLitres (void)
{
	return 10 + litreStream -> nextfloat() * 50;
};

// The probability that a car leaves without buying gas (i.e., balks)
// grows larger as the queue length gets larger, and grows smaller
// when the car requries a greater number of litres of gas, such that:
// (1) there is no balking if the queueLength is zero, and
// (2) otherwise, the probability of *not* balking is
//       (40 + litres)/(25 * (3 + queueLength))

bool DoesCarBalk (double litres, int queueLength)
{
	return queueLength > 0 && balkingStream -> nextfloat()
		> (40 + litres) / (25 * (3 + queueLength));
}

// Determine how long the service will take.
//
// Service times will have a near Normal distribution, where the mean is 150
// seconds plus 1/2 second per litre, and the standard deviation is 30 seconds.
// (It can be shown that the sum of 12 random numbers from the
// uniform distribution on (0,1) has a near Normal distribution
// with mean 6 and standard deviation 1.)

double serviceTime(double litres)
{
	double howLong = -6;

	for (int i = 1; i <= 12; i++)
		howLong += serviceStream -> nextfloat();

	return 150 + 0.5 * litres + 30 * howLong;
}
