/*Written by Andrew C. Chase for Cognitive Science 184, Winter 2000/2001*/ #include #include #include #include #include /*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; typedef struct { double call_with; double call_wo; double build; short energy; } Prey; Prey pr[NUM_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" 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; /*changed from double to float and removed a ';'*/ double fac, r, v1, v2, p; /*changed from double to float*/ 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); } } /*==========================================================*/