Code
Truth --- Code
--- Results --- Discussion
--- Downloads
Below is the code for the main program, honesty.c
Standard comments to the code are in red.
Further analysis is in green.
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
/*Definitions */
#define NUM_PREY 400
#define NUM_PRED 100
#define PRED_ATTRIBS 3
#define PREY_ATTRIBS 4
#define ENERGY 100
#define TRANSFER_VALUE 1.0 /*amount of energy taken from prey is a random
value between upper and lower value multiplied by this*/
#define GAUSS_DIVIDE 100 /*amount to divide Gauss with mean of 1 by */
int upper_value = 0;
int lower_value = 0;
float cost_to_build = 0;
float cost_to_attack = 0;
float aging_prey = 0;
float aging_pred = 0;
float batt_factor = 0;
int prey_reproductions = 0;
int pred_reproductions = 0;
/*This data structure will hold the values for individuals representing preys.
'call_with' is a percentage chance that the prey will call when battlements have
been built. 'call_wo' is a percentage chance that the prey will call when it
has not built battlements (this can be construed as "lying", assuming the prey
is using calling to indicate battlements have been built). 'build' is a percantage
representing the the chance that the prey will build battlements durring an
interaction. "Battlements" is a convention used to represent any action a prey
may undertake to make itself less desirable to the predator. In our model when
battlements are built it costs the predator more to attack, and the predator gets
less from the prey. */
typedef struct {
double call_with;
double call_wo;
double build;
short energy;
} Prey;
Prey pr[NUM_PREY]; /*An array of Preys */
/*This structure is for representing individuals within the predator population.
'attack_call' is a percentage value representing the likliehood the predator will
attack if a call has been given by the prey. 'attack_no_call' is a percentage
value representing the likliehood of a predator attack given there is no call made
by the prey. */
typedef struct {
double attack_call;
double attack_no_call;
short energy;
} Predator;
Predator prd[NUM_PRED];
/*=============================================================== */
/*Functions */
void initialize ();
int interact ();
void preyreproduce (int subject);
void predreproduce (int subject);
int energypred (int subject, int amount);
int energyprey (int subject, int amount);
void record (int loop);
void aging();
int collectvariables();
int attack(int pry, int pd, int batt, int situation);
double frand ();
double irand (double max);
double rgauss ();
/*============================================================== */
int
main()
{
int i, j, k, epochs, sweeps, records;
FILE *data_ptr; /*data_ptr = data file pointer */
if((data_ptr = fopen("data", "w"))==NULL)
printf("File Could not be opened.\n");
printf("How man interactions before aging cycle? : ");
scanf("%d", &epochs);
printf("How man aging cycles before sweep? : ");
scanf("%d", &sweeps);
printf("How man records? : ");
scanf("%d", &records);
if (collectvariables() == 0)
{
printf("problems with variable file\n");
exit(0);
}
initialize();
for (i = 0; i < records; i++)
{
record(i);
for (j = 0; j < sweeps; j++)
{
for (k = 0; k < epochs; k ++)
interact();
aging();
}
}
printf("number of prey which died: %d \nnumber of predators which died: %d \n", /
prey_reproductions, pred_reproductions);
exit(0);
}
/*==============================================================*/
/* Initialize both the predator and prey populations, filling the
attributes with random values from 0 to 1 and the Energy value being set to 100 */
void initialize ()
{
int i = 0;
int j = 0;
for (i = 0; i < NUM_PRED; i++)
{
for (j = 0; j < PRED_ATTRIBS; j++)
{
if (j == 0)
prd[i].attack_call = frand(); /*attack with call */
if (j == 1)
prd[i].attack_no_call = frand(); /*attack without call*/
if (j == 2)
prd[i].energy = irand(ENERGY); /*starting energy */
}
}
for (i = 0; i < NUM_PREY; i++)
{
for (j = 0; j < PREY_ATTRIBS; j++)
{
if (j == 0){
pr[i].call_with = frand(); /*call with battlements */
}
if (j == 1){
pr[i].call_wo = frand(); /*call with out battlements (bluff) */
}
if (j == 2){
pr[i].build = frand(); /*make battlements */
}
if (j == 3){
pr[i].energy = irand(ENERGY);
}
}
}
}
/*================================================================= */
/*Interactions between prey and predator, assuming the two see each other */
int
interact ()
{
int pry, pd; /*represent prey and predator */
int didbuild = 0, didcall = 0; /*1 is yes, 0 is no */
int enexchange = 0;
pry = irand(NUM_PREY - 1); /*assign a random (unlucky) prey */
pd = irand(NUM_PRED - 1);
/*assign a random predator
first the prey will decide whether or not to build battlements
this will be decided by generating a random value and comparing
it to the trait, choosing the higher */
if(pr[pry].build > frand())
{
didbuild = 1;
if(0 == energyprey(pry, cost_to_build))/*prey gives up energy for building */
return(0);
if(pr[pry].call_with > frand())
/*having built battlements */
didcall = 1;
}
else
{
if(pr[pry].call_wo > frand()) /*call w/o battlements */
didcall = 1;
}
attack(pry, pd, didbuild, didcall);
return(1);
}
/*=================================================================*/
/*An asexual reproduction function */
/* The function takes a single prey or predator that has died, and replaces
that prey or predator with a new one. The new replacement has its values
selected by comparing two randomly selected individuals and the individual
with the higher energy level will be the prototype from which the new
replacement is made. */
void
preyreproduce (int subject)
{
int i;
int j;
prey_reproductions += 1;
/*First reproduce Prey by taking two prey, and allowing the one with */
/*higher energy to reproduce */
i = irand (NUM_PREY - 1);
j = irand (NUM_PREY - 1);
if (i == j)
i = (i % 11) + 3; /*set i to new value if it is the same as j*/
if (pr[i].energy >= pr[j].energy) /*Compare energy values */
{
pr[subject].call_with = (pr[i].call_with + (rgauss ()));
if(pr[subject].call_with > 1.0) pr[subject].call_with = 1.0;
if(pr[subject].call_with < 0.00) pr[subject].call_with = 0.0;
pr[subject].call_wo = (pr[i].call_wo + (rgauss ())); /*rgauss "jiggles" */
/*rgauss is a function which will add some value to the new individuals
value corresponding to a Gaussian distribution ranging from .01 to -.01
In effect, this acts as a slight mutation to the individual being
reproduced to allow for evolution to select for individuals whos values
"jiggle" in the more beneficial direction */
if(pr[subject].call_wo > 1.0) pr[subject].call_wo = 1.0;
if(pr[subject].call_wo < 0.00) pr[subject].call_wo = 0.0;
pr[subject].build = (pr[i].build + (rgauss ()));
if(pr[subject].build > 1.0) pr[subject].build = 1.0;
if(pr[subject].build < 0.00) pr[subject].build = 0.0;
pr[subject].energy = ENERGY;
}
if (pr[j].energy > pr[i].energy) /*Compare energy values*/
{
pr[subject].call_with = (pr[j].call_with + (rgauss ()));
if(pr[subject].call_with > 1.0) pr[subject].call_with = 1.0;
if(pr[subject].call_with < 0.00) pr[subject].call_with = 0.0;
pr[subject].call_wo = (pr[j].call_wo + (rgauss ()));
if(pr[subject].call_wo > 1.0) pr[subject].call_wo = 1.0;
if(pr[subject].call_wo < 0.00) pr[subject].call_wo = 0.0;
pr[subject].build = (pr[j].build + (rgauss ()));
if(pr[subject].build > 1.0) pr[subject].build = 1.0;
if(pr[subject].build < 0.00) pr[subject].build = 0.0;
pr[subject].energy = ENERGY;
}
}
void
predreproduce (int subject)
{
int i;
int j;
pred_reproductions += 1;
i = irand (NUM_PRED - 1);
j = irand (NUM_PRED - 1);
if (i == j)
i = (i % 11) + 3; /*set i to knew value if it is the same as j */
if (prd[i].energy >= prd[j].energy) /*Compare energy values */
{
prd[subject].attack_call = (prd[i].attack_call + (rgauss ()));
if(prd[subject].attack_call > 1.0) prd[subject].attack_call = 1.0;
if(prd[subject].attack_call < 0.00) prd[subject].attack_call = 0.0;
prd[subject].attack_no_call = (prd[i].attack_no_call + (rgauss ()));
if(prd[subject].attack_no_call > 1.0) prd[subject].attack_no_call = 1.0;
if(prd[subject].attack_no_call < 0.00) prd[subject].attack_no_call = 0.0;
prd[subject].energy = ENERGY;
}
if (prd[j].energy > prd[i].energy) /*Compare energy values*/
{
prd[subject].attack_call = (prd[j].attack_call + (rgauss ()));
if(prd[subject].attack_call > 1.0) prd[subject].attack_call = 1.0;
if(prd[subject].attack_call < 0.00) prd[subject].attack_call = 0.0;
prd[subject].attack_no_call = (prd[j].attack_no_call + (rgauss ())); /*rgauss "jiggles"*/
if(prd[subject].attack_no_call > 1.0) prd[subject].attack_no_call = 1.0;
if(prd[subject].attack_no_call < 0.00) prd[subject].attack_no_call = 0.0;
prd[subject].energy = ENERGY;
}
}
/*===============================================================*/
/*Getting old is such a drag */
/*This function goes through the entire population and for each prey
and for each predator it calls the energy functions and either takes
away or adds to the individuals energy. The amount taken or given
is defined with the make_config executable. */
void
aging()
{
int i;
for(i = 0; i < NUM_PREY; i++)
energyprey(i, aging_prey);
for(i = 0; i < NUM_PRED; i++)
energypred(i, aging_pred);
}
/*================================================================*/
/*record averages for populations of predator and prey*/
/*Loop is simply the number passed to the argument to define how many times
the record function will take place. The loop value is set in the
make_config executable. */
void
record (int loop)
{
int i;
double callbatt = 0.0, callnobatt = 0.0, build = 0.0, preyen = 0.0;
double attackcall = 0.0, attacknocall = 0.0, preden = 0.0;
FILE *data_ptr;
if ((data_ptr = fopen("data", "a+")) == NULL)
printf("File could not be opened.\n");
else {
for (i = 0; i < NUM_PREY; i++)
{
callbatt += pr[i].call_with;
callnobatt += pr[i].call_wo;
build += pr[i].build;
preyen += pr[i].energy;
}
callbatt = callbatt/NUM_PREY;
callnobatt = callnobatt/NUM_PREY;
build = build/NUM_PREY;
preyen = preyen/NUM_PREY;
fprintf(data_ptr, "%d %.3f %.3f %.3f %.3g ", loop, callbatt, callnobatt, build, preyen);
for (i = 0; i < NUM_PRED; i++)
{
attackcall += prd[i].attack_call;
attacknocall += prd[i].attack_no_call;
preden += prd[i].energy;
}
attackcall = attackcall/NUM_PRED;
attacknocall = attacknocall/NUM_PRED;
preden = preden/NUM_PRED;
fprintf(data_ptr, "%.3f %.3f %.3g\n", attackcall, attacknocall, preden);
fclose(data_ptr);
}
}
/*================================================================*/
/*energy exchange for prey and predator*/
/*This function will take a subject, some individual, and an amount,
some amount of energy, positive or negative which the subject will
will have added to their energy. If the energy value goes below 0
after the exchange then the reproduce function is called because
the subject is dead. */
int
energypred (int subject, int amount)
{
prd[subject].energy = prd[subject].energy + amount;
if(prd[subject].energy > 100) /*don't allow energy above 100*/
prd[subject].energy = 100;
if(prd[subject].energy < 0) /*if energy below 100, dead!*/
{
predreproduce(subject);
return(0);
}
else return(1);
}
int
energyprey (int subject, int amount)
{
pr[subject].energy = pr[subject].energy + amount;
if(pr[subject].energy > 100)
pr[subject].energy = 100;
if(pr[subject].energy < 0)
{
preyreproduce(subject);
return (0);
}
else return(1);
}
/*================================================================*/
/*Attack function*/
/*This function takes a predator and a prey, a battlement value and
a situation value. The battlement value is 1 or 0, 1 representing
that battlements have been built by the prey, 0 representing they
have not. The situation value is a 0 or 1 with 0 meaning the prey
did not call and 1 meaning it did. */
int
attack(int pry, int pd, int batt, int situation)
{
double enexchange = irand(upper_value) + lower_value;
if ((situation == 1 && prd[pd].attack_call > frand()) || \
(situation == 0 && prd[pd].attack_no_call > frand()))
{
if(batt == 1)
{
if(energypred (pd, cost_to_attack) == 0)
return(0);/*costs too much to attack and pred dies*/
if(pr[pry].energy < (batt_factor * enexchange))
{
/*predator only gets what the pr has left*/
energypred(pd, pr[pry].energy);
preyreproduce(pry); /* Prey Dies */
return(0);
}
energypred(pd, (batt_factor * enexchange));
energyprey(pry, (batt_factor * -enexchange * TRANSFER_VALUE));
}
else if (batt == 0) /*could just say 'else' here*/
{
if(pr[pry].energy < enexchange)
{/*predator only gets what the prey has left*/
energypred(pd, pr[pry].energy);
preyreproduce(pry);
return(0);
}
energypred(pd, enexchange);
energyprey(pry, (-enexchange * TRANSFER_VALUE));
}
}
else if(frand() > .95)
{/*random action by predator*/
if(batt == 1)
{
if(energypred (pd, cost_to_attack) == 0)
return(0);/*costs to much to attack and pred dies*/
if(pr[pry].energy < (batt_factor * enexchange))
{/*predator only gets what the prey has left*/
energypred(pd, pr[pry].energy);
preyreproduce(pry);
return(0);
}
energypred(pd, (batt_factor * enexchange));
energyprey(pry, (batt_factor * -enexchange * TRANSFER_VALUE));
}
else if (batt == 0) /*could just say 'else' here */
{
if(pr[pry].energy < enexchange)
{/*predator only gets what the prey has left*/
energypred(pd, pr[pry].energy);
preyreproduce(pry);
return(0);
}
energypred(pd, enexchange);
energyprey(pry, (-enexchange * TRANSFER_VALUE));
}
}
}
/*================================================================*/
/*Collect all variables from a file*/
int
collectvariables()
{
FILE *cvPtr;
if((cvPtr = fopen("config.honesty", "r")) == NULL)
return(0);
else {
fscanf(cvPtr, "%d %d %f %f %f %f %f", &upper_value, &lower_value, \
&cost_to_build, &cost_to_attack, &aging_prey, &aging_pred, &batt_factor);
}
printf("%d %d %f %f %f %f %f\n", upper_value, lower_value, cost_to_build, \
cost_to_attack, aging_prey, aging_pred, batt_factor);
fclose(cvPtr);
return (1);
}
/*=================================================================*/
/*Math stuff*/
double
frand ()
{
return ((double) rand () / RAND_MAX);
}
double
irand (double max)
{
return ((double) floor (fabs (max) * frand ()));
}
/*======================================================*/
/*Gaussian distributed random numbers, from Prof. Batali */
static int rgauss_iset = 0;
static void reset_rgauss (void)
{
rgauss_iset = 0;
}
double
rgauss ()
{
static double gset;
double fac, r, v1, v2, p;
if (frand () > 0.5)
p = 1.0;
else p = -1.0;
if (rgauss_iset == 0) {
do {
v1 = frand ();
v2 = frand ();
r = v1*v1 + v2*v2;
}
while (r >= 1.0);
fac = sqrt(-2.0*log(r)/r);
gset= v1*fac;
rgauss_iset = 1;
return(p*v2*fac/GAUSS_DIVIDE);
}
else {
rgauss_iset = 0;
return(p*gset/GAUSS_DIVIDE);
}
}
/*==========================================================*/
Truth --- Code
--- Results --- Discussion
--- Downloads
|