Complete.Org: Mailing Lists: Archives: freeciv-dev: December 1999:
[Freeciv-Dev] patch: re-work flood_it() (PR#217)
Home

[Freeciv-Dev] patch: re-work flood_it() (PR#217)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-dev@xxxxxxxxxxx
Cc: bugs@xxxxxxxxxxxxxxxxxxx
Subject: [Freeciv-Dev] patch: re-work flood_it() (PR#217)
From: David Pfitzner <dwp@xxxxxxxxxxxxxx>
Date: Wed, 29 Dec 1999 06:17:32 -0800 (PST)

The flood_it() function is poorly named, and performs several tasks 
(or a subset of those tasks, or none).  

This patch replaces flood_it() with functions assign_continent_numbers() 
and setup_isledata().  Also adds field game.num_continents, and does 
some related re-org in mapgen.c, including making islands[] dynamically 
allocated (to in principle allow more continents in some cases).

This patch should have no user-visible effects (regression tested),
but in re-writing some parts I noticed some things which should 
probably be changed, relating to calculation of "goodies" for
calculating player start locations:

 1. Ocean squares are added multiple times for goodies (once per
    adjacent land tile), compared to once only for land squares;
    also usable but non-adjacent T_OCEAN (ie, 2 squares away) are
    not counted at all.

 2. Currently there is some code to increase goodies for huts, but
    it occurs before islands[] is setup/initialized, so has no 
    effect.  The patch includes adjusted code to fix this, but 
    with effect commented out for now.

-- David
diff -u -r --exclude-from exclude freeciv-cvs/common/map.c fc-adv/common/map.c
--- freeciv-cvs/common/map.c    Thu Dec 30 00:47:47 1999
+++ fc-adv/common/map.c Thu Dec 30 00:28:38 1999
@@ -95,6 +95,7 @@
   map.forestsize=MAP_DEFAULT_FORESTS;
   map.generator=MAP_DEFAULT_GENERATOR;
   map.tiles=0;
+  map.num_continents = 0;
   map.num_start_positions=0;
   map.fixed_start_positions=0;
   map.have_specials = 0;
diff -u -r --exclude-from exclude freeciv-cvs/common/map.h fc-adv/common/map.h
--- freeciv-cvs/common/map.h    Thu Dec 30 00:47:47 1999
+++ fc-adv/common/map.h Thu Dec 30 00:28:38 1999
@@ -164,6 +164,7 @@
   int num_start_positions;
   int fixed_start_positions;
   int have_specials;
+  int num_continents;
   struct tile *tiles;
   struct map_position start_positions[MAX_NUM_NATIONS];
 };
Only in fc-adv/: rm_flood_it.diff
diff -u -r --exclude-from exclude freeciv-cvs/server/civserver.c 
fc-adv/server/civserver.c
--- freeciv-cvs/server/civserver.c      Tue Dec 28 23:23:35 1999
+++ fc-adv/server/civserver.c   Thu Dec 30 00:55:09 1999
@@ -398,8 +398,10 @@
      anyway, to make the specials and huts */
   if(map_is_empty() || (map.generator == 0 && game.is_new_game))
     map_fractal_generate();
-  else 
-    flood_it(1);
+
+  if (map.num_continents==0)
+    assign_continent_numbers();
+
   gamelog_map();
   /* start the game */
 
@@ -416,10 +418,7 @@
 
     /* we don't want random start positions in a scenario which already
        provides them.  -- Gudy */
-    if(map.num_start_positions>0) {
-      flood_it(1);
-    } else {
-      flood_it(0);
+    if(map.num_start_positions==0) {
       create_start_positions();
     }
   }
diff -u -r --exclude-from exclude freeciv-cvs/server/mapgen.c 
fc-adv/server/mapgen.c
--- freeciv-cvs/server/mapgen.c Tue Dec 28 23:23:35 1999
+++ fc-adv/server/mapgen.c      Thu Dec 30 00:34:46 1999
@@ -50,9 +50,10 @@
   int goodies;
   int starters;
 };
-#define MAP_NCONT 255
-static struct isledata islands[MAP_NCONT];
+static struct isledata *islands;
 
+/* this is used for generator>1 */
+#define MAP_NCONT 255
 
 /**************************************************************************
  Just a wrapper function off the height_map, returns the height at x,y
@@ -486,79 +487,152 @@
 }
 
 /**************************************************************************
- a basic floodfill used to give every square a continent number, so we later
- on can ask which continent a given square belongs to.
+ Number this tile and recursive adjacent tiles with specified
+ continent number, by flood-fill algorithm.
+ Returns 1 if tile successfully assigned this number.
 **************************************************************************/
-static void flood_fill(int x, int y, int nr)
+static int assign_continent_flood(int x, int y, int nr)
 {
-  if (x==-1) x=map.xsize-1;
-  if (x==map.xsize) x=0;
-  if (y==-1) return;
-  if (y==map.ysize) return;
-  if (map_get_continent(x, y)) 
-    return;
+  x = map_adjust_x(x);
+  
+  if (y<0 || y>=map.ysize)             return 0;
+  if (map_get_continent(x, y))         return 0;
+  if (map_get_terrain(x, y)==T_OCEAN)  return 0;
 
-  if (map_get_terrain(x, y)==T_OCEAN){ 
-    if(is_sea_usable(x,y))
-      islands[nr].goodies+= is_good_tile(x, y);
-    return;
-  }
-  islands[nr].goodies+=is_good_tile(x, y);
   map_set_continent(x, y, nr);
-  flood_fill(x-1,y,nr);
-  flood_fill(x-1,y+1,nr);
-  flood_fill(x-1,y-1,nr);
-  flood_fill(x,y-1,nr);
-  flood_fill(x,y+1,nr);
-  flood_fill(x+1,y-1,nr);
-  flood_fill(x+1,y,nr);
-  flood_fill(x+1,y+1,nr);
+  
+  assign_continent_flood(x-1, y-1, nr);
+  assign_continent_flood(x-1, y,   nr);
+  assign_continent_flood(x-1, y+1, nr);
+  
+  assign_continent_flood(x,   y-1, nr);
+  assign_continent_flood(x,   y+1, nr);
+  
+  assign_continent_flood(x+1, y-1, nr);
+  assign_continent_flood(x+1, y,   nr);
+  assign_continent_flood(x+1, y+1, nr);
+
+  return 1;
 }
 
 /**************************************************************************
- find start points for continents and call flood_fill for all of them 
+ Assign continent numbers to all tiles.
+ Numbers 1 and 2 are reserved for polar continents if
+ map.generator != 0; otherwise are not special.
+ Also sets map.num_continents (note 0 is ocean, and continents
+ have numbers 1 to map.num_continents _inclusive_).
+ Note this is not used by generators>1 at map creation
+ time, as these assign their own continent numbers.
 **************************************************************************/
-void flood_it(int loaded)
+void assign_continent_numbers(void)
+{
+  int x, y;
+  int isle = 1;
+
+  for (y=0; y<map.ysize; y++)
+    for (x=0; x<map.xsize; x++)
+      map_set_continent(x, y, 0);
+
+  if (map.generator != 0) {
+    assign_continent_flood(0, 0, 1);
+    assign_continent_flood(0, map.ysize-1, 2);
+    isle = 3;
+  }
+      
+  for (y=0; y<map.ysize; y++) {
+    for (x=0; x<map.xsize; x++) { 
+      if (!map_get_continent(x, y) && map_get_terrain(x, y)!=T_OCEAN) {
+       assign_continent_flood(x, y, isle++);
+      }
+    }
+  }
+  map.num_continents = isle-1;
+  freelog(LOG_VERBOSE, "Map has %d continents", map.num_continents);
+}
+
+/**************************************************************************
+ Allocate islands array and fill in values.
+ Note this is only use for map.generator<=1, since others
+ setups islands and starters explicitly.
+**************************************************************************/
+static void setup_isledata(void)
 {
   int x,y;
   int good, mingood, maxgood;
-  int isles=3;
   int riches;
   int starters;
-  int oldisles, goodisles;
+  int isles, oldisles, goodisles;
   int guard1=0;
+  int firstcont;
+  int i;
 
-  if (!loaded && map.generator > 1) return;
-  /* 2,3 and 4 have fixed number of starters */
-  /* means: goodies is not initialized for 2,3,4.
-     doesn't matter now, since unused */
-  /* But we still need to initialise the continents on reload,
-     and for scenarios (generator==0) for new game. --dwp */
+  assert(map.num_continents>0);
+  
+  /* allocate + 1 so can use continent number as index */
+  islands = fc_malloc((map.num_continents+1)*sizeof(struct isledata));
 
-  for (y=0;y<map.ysize;y++)
-    for (x=0;x<map.xsize;x++)
-      map_set_continent(x, y, 0);
-  flood_fill(0,0,1);                   /* want to know where the rim is */
-  flood_fill(0,map.ysize-1,2);         /* ... */
-  for (y=0;y<map.ysize;y++)
-    for (x=0;x<map.xsize;x++) 
-      if (!map_get_continent(x, y) && map_get_terrain(x, y)!=T_OCEAN ) {
-       if(isles>=MAP_NCONT) isles= MAP_NCONT-1; 
-       islands[isles].goodies=0;
-       flood_fill(x,y,isles);
-       islands[isles].starters=0;
-       islands[isles].x=x;
-       islands[isles].y=y;
-       isles++; 
+  /* initialize: */
+  for(i=0; i<=map.num_continents; i++) {
+    islands[i].x = islands[i].y = -1;             /* flag */
+    islands[i].goodies = islands[i].starters = 0;
+  }
+
+  /* get x and y positions: (top left) */
+  for (y=0; y<map.ysize; y++) {
+    for (x=0; x<map.xsize; x++) {
+      int cont = map_get_continent(x, y);
+      if (islands[cont].x == -1) {
+       islands[cont].x = x;
+       islands[cont].y = y;
       }
- 
-  if (loaded)                 /* only make the continents if loaded game*/
-    return;
-
-  /* the arctic and the antarctic are continents 1 and 2 */
+    }
+  }
 
+  /* Add up the goodies: for useable ocean, add value to continent
+     for _every_ adjacent land tile.  This is IMO not very good,
+     because it adds potentially many times, and usable sea of
+     distance 2 from land is ignored, but this re-produces the
+     results of the previous method which used flood_fill().  --dwp
+     This is also the correct place to add S_HUT bonus.
+  */
+  for (y=0; y<map.ysize; y++) {
+    for (x=0; x<map.xsize; x++) {
+      int cont = map_get_continent(x, y);
+      if (cont) {
+       islands[cont].goodies += is_good_tile(x, y);
+       if (map_get_special(x,y) & S_HUT) {
+         islands[cont].goodies += 0; /* 3; */   /* regression testing */
+       }
+      } else {
+       assert(map_get_terrain(x, y)==T_OCEAN);
+       /* no need to check is_sea_usable(x,y), because will
+          only use for adjacent land (cont1>0) below */
+       {
+         int goodval = is_good_tile(x, y);
+         int x1, y1;
+         for (x1=-1; x1<=1; x1++) {
+           for (y1=-1; y1<=1; y1++) {
+             int cont1 = map_get_continent(x+x1, y+y1);
+             if (cont1>0) {  
+               islands[cont1].goodies += goodval;
+             }
+           }
+         }
+       }
+      }
+    }
+  }
+  
+  /* the arctic and the antarctic are continents 1 and 2 for generator>0*/
+  if (map.generator>0) {
+    firstcont = 3;
+  } else {
+    firstcont = 1;
+  }
+  isles = map.num_continents+1;
+ 
   riches=0;
-  for (x=3;x<isles;x++) {
+  for (x=firstcont; x<isles; x++) {
       riches+=islands[x].goodies;
   }
 
@@ -574,7 +648,7 @@
 
 
     /* goody goody */
-    for (x=3;x<isles;x++) {      
+    for (x=firstcont;x<isles;x++) {      
       islands[x].starters=0;
       if ( islands[x].goodies > (riches+oldisles-1)/oldisles ) 
        { 
@@ -592,7 +666,7 @@
 
     if(goodisles>game.nplayers){
       /* bloody goodies */   
-      for (x=3;x<isles;x++) {
+      for (x=firstcont;x<isles;x++) {
        if (( islands[x].goodies*4 > 3*(riches+oldisles-1)/oldisles )
            &&!(islands[x].goodies > (riches+oldisles-1)/oldisles)
            )
@@ -606,7 +680,7 @@
   
  
       /* starters are loosers */
-      for (x=3;x<isles;x++) {
+      for (x=firstcont;x<isles;x++) {
        if (( islands[x].goodies*4 > 3*(riches+oldisles-1)/oldisles )
            &&!(islands[x].goodies > (riches+oldisles-1)/oldisles)) {
          freelog(LOG_VERBOSE, "islands[x].goodies=%i",islands[x].goodies);
@@ -620,7 +694,7 @@
     }
 
     /* starters are winners */
-    for (x=3;x<isles;x++) {
+    for (x=firstcont;x<isles;x++) {
       if (islands[x].goodies > (riches+oldisles-1)/oldisles) {
        assert(!islands[x].starters);
        freelog(LOG_VERBOSE, "islands[x].goodies=%i", islands[x].goodies);
@@ -650,6 +724,7 @@
   freelog(LOG_NORMAL, _("The map has %i starting positions on %i isles."),
          starters, goodisles);
 }
+
 /**************************************************************************
   where do the different races start on the map? well this function tries
   to spread them out on the different islands.
@@ -661,6 +736,9 @@
   int dist=40;
   int x, y, j=0;
 
+  if (islands==NULL)           /* already setup for generator>1 */
+    setup_isledata();
+  
   if(dist>= map.xsize/2)
     dist= map.xsize/2;
   if(dist>= map.ysize/2)
@@ -669,7 +747,7 @@
   {
     int sum,k;
     sum=0;
-    for(k=0;k<99;k++){
+    for(k=0;k<=map.num_continents;k++){
       sum+= islands[k].starters;
       if(islands[k].starters!=0) {
        freelog(LOG_VERBOSE, "starters on isle %i", k);
@@ -698,12 +776,12 @@
     }
   }
   map.num_start_positions = game.nplayers;
+  free(islands);
+  islands = NULL;
 }
 
 /**************************************************************************
-  we have 2 ways of generation a map, 
-  1) generates normal maps like in civ
-  2) generates 7 equally sized and with equally number of specials islands
+  See stdinhand.c for information on map generation methods.
 **************************************************************************/
 void map_fractal_generate(void)
 {
@@ -960,8 +1038,9 @@
       if (!is_hut_close(x,y)) {
        number--;
        map_get_tile(x,y)->special|=S_HUT;
-       if(map_get_continent(x,y)>=2)
-         islands[(int)map_get_continent(x,y)].goodies+= 3;
+       /* Don't add to islands[].goodies because islands[] not
+          setup at this point, except for generator>1, but they
+          have pre-set starters anyway. */
       }
     }
   }
@@ -1293,6 +1372,7 @@
     }
 
     isleindex++;
+    map.num_continents++;
   }
 }
 
@@ -1302,7 +1382,10 @@
 static void initworld(void)
 {
   int x, y;
+  
   height_map = fc_malloc(sizeof(int) * map.ysize * map.xsize);
+  islands = fc_malloc((MAP_NCONT+1)*sizeof(struct isledata));
+  
   for (y = 0 ; y < map.ysize ; y++) 
     for (x = 0 ; x < map.xsize ; x++) {
       map_set_terrain(x, y, T_OCEAN);
@@ -1322,6 +1405,7 @@
       map_set_continent(x, map.ysize-2, 2);
     }
   }
+  map.num_continents = 2;
   makeisland(0, 0);
   islands[2].starters = 0;
   islands[1].starters = 0;
diff -u -r --exclude-from exclude freeciv-cvs/server/mapgen.h 
fc-adv/server/mapgen.h
--- freeciv-cvs/server/mapgen.h Wed Jul 14 21:29:06 1999
+++ fc-adv/server/mapgen.h      Wed Dec 29 23:02:51 1999
@@ -13,6 +13,7 @@
 #ifndef FC__MAPGEN_H
 #define FC__MAPGEN_H
 
+void assign_continent_numbers(void);
 void map_fractal_generate(void);
 void flood_it(int loaded);
 void create_start_positions(void);
diff -u -r --exclude-from exclude freeciv-cvs/server/maphand.c 
fc-adv/server/maphand.c
--- freeciv-cvs/server/maphand.c        Tue Dec 28 23:23:36 1999
+++ fc-adv/server/maphand.c     Wed Dec 29 23:02:51 1999
@@ -28,6 +28,7 @@
 #include "registry.h"
 
 #include "cityhand.h"
+#include "mapgen.h"            /* assign_continent_numbers */
 #include "plrhand.h"           /* notify_player */
 #include "unitfunc.h"
 
@@ -471,6 +472,8 @@
       map_get_tile(x, y)->terrain=pch-terrain_chars;
     }
   }
+
+  assign_continent_numbers();
 }
 
 /***************************************************************

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] patch: re-work flood_it() (PR#217), David Pfitzner <=