home *** CD-ROM | disk | FTP | other *** search
- /*
- Program: Critters
- Version: 1.00 02-Jun-1989
- Language: Microsoft QuickC v2.0
- Purpose: Simulates simple life forms which evolve
-
- Written by Scott Robert Ladd. No rights reserved.
- */
-
- #include "graph.h"
- #include "stddef.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include "string.h"
- #include "conio.h"
- #include "time.h"
-
-
- /* structure which defines a critter */
- struct critter
- {
- int move_gene[4];
- int energy_level;
- int posx;
- int posy;
- long int age;
- struct critter * next;
- struct critter * prev;
- };
-
- /* constants which define the program environment */
- const int start_crit = 25; /* initial number of critters */
- const int start_food = 2500; /* initial food supply */
-
- const int max_x = 600; /* maximum x dimension of "world" */
- const int max_y = 300; /* " y " " " */
-
- const int max_energy = 1000; /* max energy a critter can have */
- const int max_food = 4000; /* max amount of food in existence */
- const int max_age = 200; /* max age critter can reach w/o reproducing */
- const int max_mutant = 4; /* max magnitude of a mutation */
-
- const int food_value = 25; /* energy value of a piece of food */
- const int move_cost = 1; /* energy cost for critter to move once */
- const int repro_energy = 500; /* minimum energy for a critter to reproduce */
- const int repro_age = 100; /* minimum age for a critter to reproduce */
- const int start_energy = 500; /* initial energy level for starting critters */
- const int food_growth = 2; /* amount of food created each generation */
-
- /* boolean values for program behavior */
- const int old_age_kills = 1; /* true */
- const int mutate_parent = 1; /* true */
- const int dead_are_food = 0; /* false */
-
- /* colors of critters and food */
- const short food_color = 7; /* grey */
- const short crit_color = 15; /* white */
-
- /* movement definition table */
- const int delta_table[4][2] = { {0, -3}, {+3, 0,}, {0, +3}, {-3, 0} };
-
- /* root and tail of critter linked list */
- struct critter * first_critter = NULL;
- struct critter * last_critter = NULL;
-
- /* informational display counts */
- long int critter_count = 0;
- long int food_supply = 0;
- long int generation = 0;
-
- /* macro to get a random value between 1 and x */
- #define randval(x) ((rand() % x) + 1)
-
- /* function prototypes */
- void main(void); /* program control and logic */
- void setup(void); /* initial set-up of program */
- void reproduce(void); /* critter reproduction/death cycle */
- void movement(void); /* critter motion */
- void make_food(void); /* adds new food to world */
- void show_stats(void); /* displays current information on the world */
- int cancel(void); /* checks for a keyboard entry */
-
- void main(void)
- {
- setup();
-
- do {
- reproduce();
- movement();
- make_food();
- show_stats();
- }
- while (!cancel());
-
- _setvideomode(_DEFAULTMODE);
- }
-
- void setup(void)
- {
- int i, j, res, x, y, pval, working;
- unsigned seed;
- struct critter * temp_critter;
-
- /* initialize random number generator */
- seed = (unsigned)time(NULL);
- srand(seed);
-
- /* initialize graphics to EGA 16 color mode */
- res = _setvideomode(_ERESCOLOR);
-
- if (!res)
- {
- _setvideomode(_DEFAULTMODE);
- exit(1);
- }
-
- /* initialize linked list of critters */
- for (i = 0; i < start_crit; ++i)
- {
- temp_critter = malloc(sizeof(struct critter));
-
- if (first_critter == NULL)
- {
- temp_critter->prev = NULL;
- first_critter = temp_critter;
- }
- else
- {
- last_critter->next = temp_critter;
- temp_critter->prev = last_critter;
- }
-
- last_critter = temp_critter;
- temp_critter->next = NULL;
-
- temp_critter->energy_level = start_energy;
-
- for (j = 0; j < 4; ++ j)
- temp_critter->move_gene[j] = j + 1;
-
- temp_critter->posx = randval(max_x);
- temp_critter->posy = randval(max_y);
-
- temp_critter->age = 0;
- }
-
- /* place initial food supply */
- _setcolor(food_color);
-
- for (i = 0; i < start_food; ++i)
- {
- working = 1;
-
- do {
- x = randval(max_x);
- y = randval(max_y);
-
- pval = _getpixel(x,y);
-
- if (pval != food_color)
- {
- _setpixel(x,y);
- working = 0;
- }
-
- ++food_supply;
- }
- while (working);
- }
-
- /* set information counts */
- critter_count = start_crit;
- food_supply = start_food;
- }
-
- void reproduce(void)
- {
- int i, x, y;
- struct critter * temp_critter;
- struct critter * new_critter;
-
- ++generation;
-
- temp_critter = first_critter;
-
- while (temp_critter != NULL)
- {
- /* the critter gets older */
- ++temp_critter->age;
-
- /* if critter can reproduce, it does */
- if ((temp_critter->energy_level >= repro_energy)
- && (temp_critter->age >= repro_age))
- {
- /* allocate a new critter */
- new_critter = malloc(sizeof(struct critter));
-
- if (new_critter == NULL)
- {
- _setvideomode(_DEFAULTMODE);
- exit(3);
- }
-
- /* add new critter to end of critter list */
- new_critter->prev = last_critter;
- new_critter->next = NULL;
- last_critter->next = new_critter;
- last_critter = new_critter;
-
- /* set new energy levels for parent and child */
- temp_critter->energy_level = temp_critter->energy_level / 2;
- new_critter->energy_level = temp_critter->energy_level;
-
- /* inherit the old genes */
- for (i = 0; i <= 3; ++i)
- new_critter->move_gene[i] = temp_critter->move_gene[i];
-
- /* select gene which is mutatated! */
- for (i = randval(4) - 1; i <= 3; ++i)
- new_critter->move_gene[i] += randval(max_mutant);
-
- /* if parent mutates... */
- if (mutate_parent)
- {
- for (i = randval(4) - 1; i <= 3; ++i)
- temp_critter->move_gene[i] += randval(max_mutant);
- }
-
-
- /* put the new critter in the same place as its parent */
- new_critter->posx = temp_critter->posx;
- new_critter->posy = temp_critter->posy;
-
- ++critter_count;
-
- new_critter->age = 0;
- temp_critter->age = 0;
- }
- /* check to see if the critter dies */
- else if ((temp_critter->energy_level == 0)
- || ((old_age_kills) && (temp_critter->age > max_age)))
- {
- --critter_count;
-
- /* if all critters have died, end the program */
- if (critter_count <= 0)
- {
- show_stats();
-
- while (!cancel())
- /* empty */ ;
-
- _setvideomode(_DEFAULTMODE);
-
- exit(2);
- }
-
- /* delete character from linked list */
- if (temp_critter->prev == NULL)
- {
- first_critter = temp_critter->next;
- first_critter->prev = NULL;
- }
- else if (temp_critter->next == NULL)
- {
- last_critter = temp_critter->prev;
- last_critter->next = NULL;
- }
- else
- {
- temp_critter->prev->next = temp_critter->next;
- temp_critter->next->prev = temp_critter->prev;
- }
-
- /* remove body of dead critter */
- for (x = temp_critter->posx - 1; x <= temp_critter->posx + 1; ++x)
- {
- for (y = temp_critter->posy - 1; y <= temp_critter->posy + 1; ++y)
- {
- if (dead_are_food)
- _setcolor(food_color);
- else
- _setcolor(0);
-
- _setpixel(x,y);
- }
- }
-
- if (dead_are_food)
- food_supply += 9;
-
- free(temp_critter);
- }
-
- temp_critter = temp_critter->next;
- }
- }
-
- void movement(void)
- {
- int i, x, y;
- int pval, move;
- struct critter * temp_critter;
-
- temp_critter = first_critter;
-
- while (temp_critter != NULL)
- {
- /* erase critter from old position */
- for (x = temp_critter->posx - 1; x <= temp_critter->posx + 1; ++x)
- {
- for (y = temp_critter->posy - 1; y <= temp_critter->posy + 1; ++y)
- {
- _setcolor(0);
- _setpixel(x,y);
- }
- }
-
- /* select movement */
- move = randval(temp_critter->move_gene[3]);
-
- for (i = 0; move > temp_critter->move_gene[i]; ++i)
- /*empty*/;
-
- /* adjust critters position */
- temp_critter->posx += delta_table[i][0];
- temp_critter->posy += delta_table[i][1];
-
- /* wrap around the edges of the world if needed */
- if (temp_critter->posx < 1)
- temp_critter->posx = max_x;
-
- if (temp_critter->posy < 1)
- temp_critter->posy = max_y;
-
- if (temp_critter->posx > max_x)
- temp_critter->posx = 1;
-
- if (temp_critter->posy > max_y)
- temp_critter->posy = 1;
-
- /* assess movement cost */
- temp_critter->energy_level -= move_cost;
-
- /* redraw critter at new position */
- for (x = temp_critter->posx - 1; x <= temp_critter->posx + 1; ++x)
- {
- for (y = temp_critter->posy - 1; y <= temp_critter->posy + 1; ++y)
- {
- _setcolor(crit_color);
- pval = _setpixel(x,y);
-
- /* if pixel covered is a food particle, consume it! */
- if (pval == food_color)
- {
- if (temp_critter->energy_level < max_energy)
- temp_critter->energy_level += food_value;
-
- --food_supply;
- }
- }
- }
-
- temp_critter = temp_critter->next;
- }
- }
-
- void make_food(void)
- {
- int i, x, y, pval, working;
-
- if (food_supply >= max_food)
- return;
-
- _setcolor(food_color);
-
- /* drop pieces of food in blank spots */
- for (i = 0; i < food_growth; ++i)
- {
- working = 1;
-
- do {
- x = randval(max_x);
- y = randval(max_y);
-
- pval = _getpixel(x,y);
-
- if ((pval != crit_color) && (pval != food_color))
- {
- _setpixel(x,y);
- working = 0;
- }
-
- ++food_supply;
- }
- while (working);
- }
- }
-
- void show_stats(void)
- {
- char buffer[78];
-
- _settextcolor(crit_color);
-
- sprintf(buffer,"generation: %6ld, critters: %5ld, food: %5ld",
- generation, critter_count, food_supply);
-
- _settextposition(24,1);
- _outtext(buffer);
- }
-
- int cancel(void)
- {
- if (kbhit())
- {
- if (!getch()) getch();
- return 1;
- }
-
- return 0;
- }
-