/*****
 *	LewObjects.h  
 *  The Organism, Population and Context objects necessary for implementing the 
 *  Lewontin model.
 *
 *****/

#pragma once

	//	NOTE:
	//	This example uses "struct" declarations
	//	for classes to make sure that all the
	//	members are public

#include <stdio.h>


#define RANDPERCENT 101
#define PERCENT 100
#define MAXCHAR 256
#define TAGLENGTH 8   /*tags are 1 byte long.*/
#define MUTRANGE 50   /*The range over which a random gene may differ from the
						parental gene. (e.g., + or - 50) */
#define MUTSCALER 1.5   /*Mutations happen on the scale of 1 / pow(gene, MUTSCALER) */
#define GENGAP 0.4		/*Percent of organisms that die every generation - simulates
						  the carrying capacity of the environment.*/
#define MAXLINELENGTH 80  /*Maximum number of characters in a line input from user.*/

#define REWARD 2  /*This defines how much an organism is rewarded for their pursuit as
					compared to their escape.  With REWARD = 2, you get the prisoner's
					dilemma.  If it is 1 then you have a symmetrical interaction.  If
					it is 0 then organisms only interact one way - through their 
					escape tags (matched to their opponent's pursuit tag).*/
#define POISSONSCALE 50.0 /*If mutation = 100 (%) then (mutation / POISSONSCALE)^3 = 8
						    which can be used for lambda in a poisson distribution of
						    the number of bit flips in*/
#define POISSONPOWER 3

/*Forward declarations ------------*/

class cContext;

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


#if __cplusplus
class cOrganism  
#else
class cOrganism : indirect
#endif
{
	unsigned char longevity;  /*Percent chance of dying in a time step.*/
	unsigned char mutation; /*Percent of genetic determination of offspring's genes.*/
  public:
	unsigned char pursue;	/*the "offense" tag.*/
	unsigned char escape; 	/*the "defense" tag.*/
  protected:
	Boolean alive;				/*Flag to indicate alife (TRUE) or dead (FALSE).*/
	int fitness;				/*fitness level determined by interactions with others.*/
	int age;			/*The number of time steps the organism has lived.*/
	int num_offspring; /*The number of offspring it has produced.*/
	
	/*Methods -------------------*/
	
	public:

		cOrganism(void); /*initializes an organism at time of creation.*/

		Boolean aging();  /*check for death by senescence.*/
		void die() {alive = FALSE;}		 /*kick the bucket.*/
		void ruach() {alive = TRUE;}  /*Ruach is the breath of life.*/
		void give_birth(cOrganism *progeny);	 /*Produce an offpring.*/
		void be_born(unsigned char longe, unsigned char mutat, unsigned char purs,
						 unsigned char esc);  /*Initialize new born from parental genes.*/
		void interact(cOrganism *other, double pursreward, 
					  double escreward); /*compare tags with another.*/
		Boolean living() {return alive;} /*returns the "alive" instance variable.*/
		void print_state(int id); /*printf's its state.*/
		void save_state(FILE *endfp);  /*save's the organism's state in the end file.*/
		void new_turn() {fitness = 0;} /*Sets up the organism for a new turn (clearing fitness).*/
		int get_fitness() {return fitness;} /*returns the organism's fitness.*/
		unsigned char get_longevity() {return longevity;}
		unsigned char get_mutation() {return mutation;}
		void inc_age() {age++;}
		int get_age() {return age;}
		int get_num_offspring() {return num_offspring;}
		
	protected:
		
		unsigned char repro_tag(unsigned char tag, unsigned char mutat); /*mutates and returns a tag.*/
		unsigned char repro_gene(unsigned char gene, unsigned char mutat); /*mutates and returns a gene.*/
};


#if __cplusplus
struct cPopulation {				// Compiling with Symantec C++!
#else
struct cPopulation : indirect {	// ...or with THINK C!
#endif

	cOrganism **orgs;			/*An array of pointers to organisms.*/
	unsigned int next_competitor; /*The organisms who will be examined next for 
									death by competition.*/
	unsigned int *corpses;	/*A stack of empty slot numbers in the orgs array.*/
	unsigned int next_corpse; /*A pointer to the top of the corpses stack.*/
	unsigned int max_corpses; /*The actual number of organisms that die in a generation.*/
	int next_parent; /*Stores who will be allowed to start reproducing next turn.*/
	int numorgs;  /*The number of organisms in the population (popsize)*/
	double ave_fitness; /*The average fitness of the population*/
	unsigned int radius; /*The radius of interaction for competition.*/

	void init_pop(cContext *context);
	~cPopulation(); /*The destructor for the cPopulation object.*/
	void competition(cContext *context); /*The organisms interact.*/
	void update_pop(cContext *context); /*Organisms die and reproduce.*/
	void print_pop();
	void reset_pop(cContext *context); /*Creates a new random population (once init_pop has been done).*/
	void save_pop(FILE *endfp, cContext *context);  /*Saves the current population in the end file.*/
	
	protected:
		void death_by_competition();
		void death_by_senescence();
		void reproduction(cContext *context);
	
		int get_next_corpse(); /*Returns -1 if there are no more corpses, 
													otherwise it pops the next corpse off the 
											      top of the corpses stack.*/
		void bury(int corpse_id); /*Pushes a new corpse onto the corpses stack.*/								

};


#if __cplusplus
struct cContext 				// Compiling with Symantec C++!
#else
struct cContext : indirect 	// ...or with THINK C!
#endif
{
	unsigned int num_trials;
	unsigned int num_high_winners;
	unsigned int num_ties;
	unsigned int current_trial;
	unsigned int pop_size;
	unsigned int time_step;
	unsigned int max_iterations;
	long randseed;
	unsigned int radius; /*The range of interactions.*/
	float gengap;
	float pursuit_factor;
	float escape_factor;
	unsigned int lowmut;
	unsigned int highmut;
	char saving; /*y or n, saving the log files*/
	char prefix[MAXLINELENGTH]; /*Prefix for the file names.*/
	char endfile[MAXLINELENGTH]; /*Name of the end file.*/
	FILE *endfp; /*pointer to the end file.*/
	
	/*Methods ------------*/
	
	cContext();		/*The constructor: asks the user for pop_size and max_iterations.*/
	void check_winner(float ave_mutation); /*increment num_high_winners and num_ties*/
	Boolean running(float ave_mutat);  /*Returns TRUE if time_step < max_iterations*/
								 
};


/* Headers ---------------------------------------------------------------*/

Boolean check_gene(unsigned char gene);
