//=================================================== file = lotterySim.c =====
//= A Monte Carlo simulation of a lottery                                     =
//=============================================================================
//= Notes:                                                                    =
//=   1) Need to set M and N in #defines                                      =
//=   1) Need to initialize N digits (all unique and from 1 to M)             =
//=---------------------------------------------------------------------------=
//= Build: bcc32 lotterySim.c                                                 =
//=---------------------------------------------------------------------------=
//= Execute: lotterySim                                                       =
//=---------------------------------------------------------------------------=
//= History: KJC (06/02/09) - Genesis (from baby.c)                           =
//=============================================================================
//----- Include files ---------------------------------------------------------
#include <stdio.h>            // Needed for printf()
#include <stdlib.h>           // Needed for rand()

//----- Constants -------------------------------------------------------------
#define         M        10   // Number of balls in bucket
#define         N         3   // Number of balls to select
#define NUM_PLAYS 100000000   // Number of plays to run

//----- Function prototypes ---------------------------------------------------
void shuffle(int *X, int numElements);    // Shuffling function
unsigned int randInt(unsigned int seed);  // RNG

//===== Main program ==========================================================
int main(void)
{
  int    ball[M];             // Balls put in bin and shuffled
  int    num[N];              // Digits picked
  int    selectedBall[N];     // Selected balls
  int    matchCount;          // Digit match counter
  int    winCount;            // Win counter (selected digits match balls pulled)
  int    i, j, k;             // Loop indexes

  // Initialize with N digits picked (all unique and from 1 to M)
  num[0] = 1;
  num[1] = 2;
  num[2] = 3;

  // Initialize the RNG
  randInt(1);

  // Main simulation loop
  printf("BEGIN...  \n");
  winCount = 0;
  for (i=0; i<NUM_PLAYS; i++)
  {
    // Output simulation progress in 10% clicks
    if ((i % (NUM_PLAYS / 10)) == 0)
      printf("  %3f %% \n", 100.0 * ((double) i / NUM_PLAYS));

    // Put M balls in the bin
    for (j=0; j<M; j++)
      ball[j] = (j+1);

    // Shuffle the balls
    shuffle(ball, M);

    // Select the first N balls
    for (j=0; j<N; j++)
      selectedBall[j] = ball[j];

    // Test if balls match picked numbers (in any order)
    matchCount = 0;
    for (j=0; j<N; j++)
      for (k=0; k<N; k++)
        if (num[j] == selectedBall[k]) matchCount++;

   // Determine if it is a "win" (all N numbers matched in above test)
   if (matchCount == N) winCount++;
  }
  printf("END! \n");

  // Output parameters and resulting probability of winning
  printf("Number of balls (M)           = %d \n", M);
  printf("Number of digits per play (N) = %d \n", N);
  printf("Number of plays (NUM_PLAYS)   = %d \n", NUM_PLAYS);
  printf("----------------------------------------------------------- \n");
  printf("Number of wins     = %d \n", winCount);
  printf("Probability of win = %f \n", (double) winCount / NUM_PLAYS);

  return(0);
}

//===========================================================================
//=  Function to shuffle series X                                           =
//===========================================================================
void shuffle(int *X, int numElements)
{
  int    from_index;          // From index
  int    to_index;            // To index
  int    temp;                // Temporary value
  int    i, j;                // Loop index

  // Do a complete shuffle numElements times
  for (i=0; i<numElements; i++)
    for (j=0; j<numElements; j++)
    {
      // Determine random from_index and to_index
      from_index = j;
      to_index = randInt(0) % numElements;

      // Swap 'em
      temp = X[from_index];
      X[from_index] = X[to_index];
      X[to_index] = temp;
    }
}

//=========================================================================
//= Multiplicative LCG                                                    =
//=   - From R. Jain, "The Art of Computer Systems Performance Analysis," =
//=     John Wiley & Sons, 1991. (Page 443, Figure 26.2)                  =
//=   - Use seed > 0 to seed the RNG, seed == 0 to get RNG values         =
//=========================================================================
unsigned int randInt(unsigned int seed)
{
  const long  a =      16807; // Multiplier
  const long  m = 2147483647; // Modulus
  const long  q =     127773; // m div a
  const long  r =       2836; // m mod a
  static long x;              // Random int value
  long        x_div_q;        // x divided by q
  long        x_mod_q;        // x modulo q
  long        x_new;          // New x value

  // Seed the RNG
  if (seed > 0) x = seed;

  // RNG using integer arithmetic
  x_div_q = x / q;
  x_mod_q = x % q;
  x_new = (a * x_mod_q) - (r * x_div_q);
  if (x_new > 0)
    x = x_new;
  else
    x = x_new + m;

  // Return a random value between 0.0 and 1.0
  return(x);
}

