/* gLife - An Artificial Life implementation using GNOME * * Copyright (C) 1999 Ali Abdin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "glife.h" #include "data.h" #include "simulation.h" #include "feedback.h" #include "drawing.h" TerrainType terrain[MAXCOL+1][MAXROW+1]; GList *animal = NULL; /* FIXME: Move defines to data.h or even better - customize this*/ #define MAXFOOD 10 /* Random Amount of food on terrain */ #define RANDFOODGEN 10 /* How fast food regenerates on terrain */ void terrain_setup(void); void erase_animals(void); void draw_terrain(void); gboolean animal_exists (gint, gint); void del_animal (gint, gint); void add_animal (gchar, gint, guint, guint, guint, guint, guint, gint, gint); static void add_ranimal (gint, gint); AnimalType *animal_at (gint, gint); void print_list(void); void animal_setup(void); void init_terrain_data(void); void init_terrain_data () { gint row,col; for (col = 0; col <= MAXCOL; col++) for (row = 0; row <= MAXROW; row++) { terrain[col][row].foodamt = -1; terrain[col][row].foodrep = -1; terrain[col][row].occupied = FALSE; terrain[col][row].anim = NULL; } } AnimalType * animal_at (gint posx, gint posy) { /* GList *tmp; AnimalType *tmpanim; */ if ((posx<=0) || (posx>MAXCOL+1) || (posy<=0) || (posy>MAXROW+1)) return NULL; /* Out of grid/terrain */ /* tmp = animal; while (tmp) { tmpanim = tmp->data; if ((tmpanim->posx == posx) && (tmpanim->posy == posy)) { return tmpanim; } tmp = g_list_next (tmp); } */ return (terrain[posx-1][posy-1].anim); g_assert_not_reached(); /* return NULL; */ } gboolean animal_exists (gint posx, gint posy) { #if 0 AnimalType *tmpanim; GList *temp; temp = animal; while (temp) { tmpanim = (AnimalType *)temp->data; if ((tmpanim->posx == posx) && (tmpanim->posy == posy)) return TRUE; temp = g_list_next (temp); } return FALSE; #endif #if 1 g_assert ((posx > 0) && (posx <= 25)); g_assert ((posy > 0) && (posy <= 25)); if (terrain[posx-1][posy-1].occupied) return TRUE; else return FALSE; g_assert_not_reached(); #endif } void add_animal (gchar sex, gint age, guint vision, guint metafood, guint speed, guint storefood, guint maxage, gint posx, gint posy) { AnimalType *new; gchar *message; g_assert ((posx>0) && (posx<=MAXCOL+1)); g_assert ((posy>0) && (posy<=MAXROW+1)); g_assert ((sex == 'm') || (sex == 'M') || (sex == 'f') || (sex == 'F')); g_assert ((age >= 0) && (vision > 0) && (metafood > 0) && (speed > 0)); new = g_malloc0(sizeof(AnimalType)); new->sex = sex; new->age = age; new->vision = vision; new->metafood = metafood; new->speed = speed; new->storefood = storefood; new->maxage = maxage; new->posx = posx; new->posy = posy; /* posx posy is between 1 and 25, terrain is between 0 and 24 */ terrain[posx-1][posy-1].occupied = TRUE; terrain[posx-1][posy-1].anim = new; if (ruleset.log2screen) { message = g_strdup_printf (_("New animal at %d,%d\n"),posx,posy); glife_log (message); g_free (message); } animal = g_list_prepend (animal, new); /* animal = g_list_reverse (animal); */ } void del_animal (gint posx, gint posy) { GList *temp; AnimalType *anim; temp = animal; while (temp != NULL) { anim = (AnimalType *)temp->data; if ((anim->posx == posx) && (anim->posy == posy)) { temp = g_list_remove (animal, temp->data); /* temp is the GLOBAL animal list without the removed item */ g_free (anim); /* Free memory */ /* animal = temp = g_list_first (temp); */ animal = g_list_first (temp); terrain[posx-1][posy-1].occupied = FALSE; terrain[posx-1][posy-1].anim = NULL; /* Reset animal and temp to the /FIRST/ list item */ /* the above may be confusing but is correct - trust me */ } temp = g_list_next (temp); } } static void add_ranimal (gint posx, gint posy) { gchar sex; gint tmp, age, vision, metafood, speed, storefood; gint maxage; age = 1; /* tmp = 1 + (gint) (100.0*rand()/(RAND_MAX+1.0)); */ tmp = RAND (0,100); if (tmp < 50) sex = 'M'; else sex = 'F'; /* vision = 1 + (gint) (3.0*rand()/(RAND_MAX+1.0)); metafood = 1 + (gint) (4.0*rand()/(RAND_MAX+1.0)); speed = 1 + (gint) (3.0*rand()/(RAND_MAX+1.0)); */ vision = RAND (1,3); metafood = RAND (1,4); speed = RAND (1,3); storefood = RAND (50, 100); maxage = RAND (ruleset.minmaxage, ruleset.maxmaxage); add_animal (sex, age, vision, metafood, speed, storefood, maxage, posx, posy); } #if 0 void draw_terrain() { GtkWidget *w; GtkProgress *progress; gint col,row; gfloat i; i = 0; w = glade_xml_get_widget (glife.xml, "appbar1"); progress = gnome_appbar_get_progress (GNOME_APPBAR (w)); gnome_appbar_push (GNOME_APPBAR (w), _("Initializing Terrain...")); for (col = 0; col <= (height / INTERVAL); col++) for (row = 0; row <= (width / INTERVAL) ; row++) { gtk_progress_set_percentage (GTK_PROGRESS (progress), i); terrain[x][y].ellipse = draw_circle (territems, RADSIZE(terrain[x][y].foodamt), (x * 15.0)/2, (y * 15.0)/2, terrcolor); gtk_object_set_data (GTK_OBJECT(terrain[x][y].ellipse), "type", "terrain"); /* Don't understand why we divide by two - but it works */ while (gtk_events_pending()) gtk_main_iteration(); i += 1.0/((MAXCOL+1) * (MAXROW+1)); } gnome_appbar_pop (GNOME_APPBAR (w)); gtk_progress_set_percentage (GTK_PROGRESS (progress), 0.0); } #endif #if 0 void print_list () { GList *tmp; AnimalType *temp; tmp = animal; while (tmp) { temp = tmp->data; g_print ("SEX: %c\n",temp->sex); tmp = g_list_next (tmp); } } #endif #if 0 void animal_init() { gint x, y, i; GtkWidget *w; GtkProgress *progress; GtkWidget *text; gfloat p; p = 0; /* g_print ("Creating %d animals\n",ruleset.numanimals); */ w = glade_xml_get_widget (glife.xml, "appbar1"); text = glade_xml_get_widget (glife.xml, "textbox"); gtk_text_freeze (GTK_TEXT (text)); progress = gnome_appbar_get_progress (GNOME_APPBAR (w)); gnome_appbar_push (GNOME_APPBAR (w), _("Initializing Animals...")); for (i = 1; i <= ruleset.numanimals; i++) { do { x = 1+(gint) (25.0*rand()/(RAND_MAX+1.0)); y = 1+(gint) (25.0*rand()/(RAND_MAX+1.0)); } while (animal_exists(x,y) == TRUE); add_ranimal (x, y); /* Add a random animal to that spot */ gtk_progress_set_percentage (GTK_PROGRESS (progress), p); p += 1.0/ruleset.numanimals; while (gtk_events_pending()) gtk_main_iteration(); } gnome_appbar_pop (GNOME_APPBAR (w)); gtk_progress_set_percentage (GTK_PROGRESS (progress), 0.0); gtk_text_thaw (GTK_TEXT (text)); } #endif void animal_setup() { gint x,y,i; gboolean temp; temp = ruleset.log2screen; ruleset.log2screen = FALSE; for (i = 1; i <= ruleset.numanimals; i++) { do { /* x = 1+(gint) (25.0*rand()/(RAND_MAX+1.0)); */ x = RAND (1,25); /* y = 1+(gint) (25.0*rand()/(RAND_MAX+1.0)); */ y = RAND (1,25); } while (animal_exists(x,y) == TRUE); add_ranimal (x, y); /* Add a random animal to that spot */ } ruleset.log2screen = TRUE; } void terrain_setup() { gint x,y; for (x = 0; x <= MAXCOL; x++) for (y = 0; y <= MAXROW; y++) { /* terrain[x][y].foodamt = 1+(gint) (MAXFOOD*rand()/(RAND_MAX+1.0)); terrain[x][y].foodrep = 1+(gint) (RANDFOODGEN*rand()/(RAND_MAX+1.0)); */ terrain[x][y].foodamt = RAND (1,MAXFOOD); terrain[x][y].foodrep = RAND (1,RANDFOODGEN); terrain[x][y].occupied = FALSE; } /* draw_terrain(); */ } void erase_animals() { #if 1 GList *tmp; tmp = animal; while (tmp) { AnimalType *anim; anim = tmp->data; g_assert (anim != NULL); del_animal (anim->posx, anim->posy); tmp = g_list_first (animal); } #endif }