        
/*  Suppose we have two network nodes, each connected to one 
    transmission line.  Time is divided into slots named slot 0, slot 
    1, slot 2, etc. Each node has one message to send, taking one time 
    unit to transmit.  

    If both nodes attempt to transmit during the same time slot, they 
    will "collide" and neither transmission is successful.  Assume there 
    was a collision in slot 0.

    In any given time slot, each node which has not yet successfully
    transmitted either tries to send or not, with probability P and 1-P, 
    respectively.  This will be done via a random number generator in
    the NIC at each node.
    
    The purpose of the random send/refrain-from-send decision is to
    prevent perpetual collisions.

    After a node has successfully transmitted, it no longer attempts
    transmission in future slots.  Assume, though, that the remaining
    node does not know that the node has dropped out of contention,
    and will continue to generate random numbers at each time slot
    to decide whether to try sending or not, as before.

    Let T denote the time slot in which the process completes, i.e. 
    the final successful transmission occurs. 

    The simulation will find (approximately) the quantities P(T = 3)
    and P(collision in slot 1 | T = 4).  */


#include <stdlib.h>  // needed for RAND_MAX 

#define NNODES 2  // number of nodes 

// states of a node
#define MSG_PENDING 0 
#define DONE 1  // this node done transmitting 
#define TRIED 2  // this node tried transmitting in this slot 
#define REFRAINED 3  // this node tried transmitting in this slot 

#define NREPS 100000  // number of times we will repeat the experiment 

int NT3 = 0,  // number of times T = 3 
    NT4 = 0,  // number of times T = 4 
    NC1T4 = 0,  /* number of times there is a collision in slot 1,
                   AMONG those times in which T = 4 */
    CollAt1,  // a collision occurred in slot 1  
    State[NNODES],  // node I done yet? 
    NDone,  // number of nodes done transmitting 
    Slot,  // current time slot 
    NTries,  // number of nodes which try to send 
    T;  // completion time 

float P; /* probability that a node will send in the next time slot */

/* the function Rnd(Prob) simulates a random event of probability
   Prob, with the return value 1 meaning the event occurred and 0
   meaning that it did not occur */

int Rnd(float Prob)

{  return((rand() < Prob * RAND_MAX));  }

Init()  /* initializes for this repetition of the experiment */

{  int Node;

   for (Node = 0; Node < NNODES; Node++)  {
      State[Node] = MSG_PENDING;  
   }

   NDone = 0;
}

DoSlot()  /* simulate the actions in this time slot */ 

{  int Node;

   NTries = 0;

   /* first, see how many nodes try to send */
   for (Node = 0; Node < NNODES; Node++)  {
      // do this node if it still has a message to send
      if (State[Node] != DONE)  {
         // generate random number to see if try to send
         if (Rnd(P))  {
	    State[Node] = TRIED;
	    NTries++; 
	 }
	 else State[Node] = REFRAINED;
      }
   }

   // if NTries is exactly 1, then determine the node which tried to 
   // send, and set its state to DONE 
   if (NTries == 1)  {
      for (Node = 0; Node < NNODES; Node++)  {
         if (State[Node] == TRIED)  {
            State[Node] = DONE;
            NDone++;
	    break;
         }
      }
   }

}

DoExperiment()

{  int Node;

   Init();
   for (Slot = 1; ; Slot++)  {
      DoSlot();
      if (Slot == 1) CollAt1 = (NTries > 1);
      if (NDone == NNODES)  {
         T = Slot;
         return; 
      }
   }
}

UpdateCounts()

{  if (T <= 3) NT3++;
   if (T == 4)  {
      NT4++;
      if (CollAt1) NC1T4++;
   }
}

PrintResults()

{  printf("P(T <= 3) = %f\n",((float) NT3)/NREPS);
   printf("P(coll in slot 1 | T = 4) = %f\n",((float) NC1T4)/NT4);
}

main(argc,argv)
   int argc; char **argv;

{  int I;

   sscanf(argv[1],"%f",&P);

   for (I = 0; I < NREPS; I++)  {
      DoExperiment();
      UpdateCounts();
   }

   PrintResults();
}

