home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
microcrn
/
issue_49.arc
/
CRITTERS.ARC
/
CRITTERS.C
next >
Wrap
C/C++ Source or Header
|
1989-06-02
|
12KB
|
423 lines
/*
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;
}