<URL: http://bugs.freeciv.org/Ticket/Display.html?id=15947 >

> [bjo...@gmail.com - Wed Oct 11 08:30:52 2006]:
> 
> So I fixed fill_island_rivers(..) as best I could with my
> rusty programming skills.

I tested your patch and it works well. In the attached
patches I made some minor formatting and style improvements,
and made a version of the patch for trunk.

There are some places that look a little weird to me, or
I just cannot figure out what they are supposed to do,
though this is mostly in the code prior to your changes:

- What is the point of the variable 'k'? And what exactly
  does the 'i == k' test mean?
- Why do you multiply failsafe by 5?
- What is the point of 'myrand(100) < coast', since 'coast'
  is always equal to 1 hence the expression only ever has
  a 1% chance of being true.

These all have pretty minor consequences, so if nobody knows
the answers I guess I'll just leave the code as is.


> River mouths can now only be surrounded by 2 ocean tiles,
> only 1 of which is cardinal. This gets rid of the hideous
> corner / peninsular 2 or 3 mouthed river outlets. Makes it
> look more natural too, especially when they start from an
> inlet or landlocked lake. Also ensures ~90% of the time
> there are 2 directions the river can go from the mouth,
> pushing the river further inland and usually making it
> more than 1 tile long.

I like the way rivers end up looking with these conditions.


> Increased the amount of river tiles generated by 75%
> for the island generator. I figure rivers will be more
> important now the capital gets corruption and a 75%
> production bonus under despotism. High production tiles
> that still produce trade are best in this situation.
> Also in gen1 most inland tiles are mountains / hills,
> it's a lot harder to irrigate inland gen3 islands with
> random terrain placement.  I really wish rivers were still
> a pregame option instead of having to turn the world into
> swamp and jungle.

I'm not sure that adding a hard-coded 75% increase is
the best solution. Anyway it is fine for now; it would
not be hard at all to implement a 'rivers' setting that
controls the amount of rivers the generator places. I'll
submit this in another ticket after this one.


> Increased the rivers aversion to ocean, and reduced its
> windiness and tendency to fork. This makes it go further
> inland and windy forking rivers ain't as useful for unit
> movement / irrigation.

Ok.


> Changed all the cardinal / percent - TRUE's & FALSE's into
> constants so the code is more readable. Just picked the
> m_ prefix out of thin air for map.h .  Should I of used
> #DEFINES or just commented every line like the generator1
> river function instead ?.

The static const values are fine I suppose, though I renamed
them to have a "C_" prefix (for "count", since they affect
the terrain counting function) and to use all uppercase.
Possibly these could be turned into enum flag values and
the two boolean arguments to the counting functions reduced
to one. 


> Split some checks into helper functions making the code
> more readable.

Good.


> Doesn't generate proper rivers for the hex2t tileset.
> Although that tileset doesn't create proper coastlines
> either and uses a different hex layout to isophex so I'll
> assume my code isn't at fault.

I'm not sure what you mean by proper rivers, since when
I tried a hex topology and the hex2t tileset with gen3,
rivers were generated alright. Perhaps the bug causing
whatever you found wrong before has since been fixed.


-----------------------------------------------------------------------
ある日、たまたま川のそばで遊んでいた。
diff --git a/common/map.h b/common/map.h
index f6f6a1e..58cbff4 100644
--- a/common/map.h
+++ b/common/map.h
@@ -77,6 +77,12 @@ enum topo_flag {
   TF_HEX = 8
 };
 
+/* Parameters for terrain counting functions. */
+static const bool C_ADJACENT = FALSE;
+static const bool C_CARDINAL = TRUE;
+static const bool C_NUMBER = FALSE;
+static const bool C_PERCENT = TRUE;
+
 #define MAP_IS_ISOMETRIC (topo_has_flag(TF_ISO) || topo_has_flag(TF_HEX))
 
 #define CURRENT_TOPOLOGY (map.topology_id)
diff --git a/server/generator/mapgen.c b/server/generator/mapgen.c
index 51495a1..a3d8396 100644
--- a/server/generator/mapgen.c
+++ b/server/generator/mapgen.c
@@ -1494,15 +1494,53 @@ static void fill_island(int coast, long int *bucket,
 }
 
 /**************************************************************************
-  fill an island with rivers
+  Returns TRUE if ptile is suitable for a river mouth.
+**************************************************************************/
+static bool island_river_mouth_suitability(const struct tile *ptile)
+{
+  int num_card_ocean, pct_adj_ocean, num_adj_river;
+
+  num_card_ocean = count_ocean_near_tile(ptile, C_CARDINAL, C_NUMBER);
+  pct_adj_ocean = count_ocean_near_tile(ptile, C_ADJACENT, C_PERCENT);
+  num_adj_river = count_special_near_tile(ptile, C_ADJACENT, C_NUMBER,
+                                          S_RIVER);
+
+  return (num_card_ocean == 1 && pct_adj_ocean <= 35
+          && num_adj_river == 0);
+}
+
+/**************************************************************************
+  Returns TRUE if there is a river in a cardinal direction near the tile
+  and the tile is suitable for extending it.
+**************************************************************************/
+static bool island_river_suitability(const struct tile *ptile)
+{
+  int pct_adj_ocean, num_card_ocean, pct_adj_river, num_card_river;
+
+  num_card_river = count_special_near_tile(ptile, C_CARDINAL, C_NUMBER,
+                                           S_RIVER);
+  num_card_ocean = count_ocean_near_tile(ptile, C_CARDINAL, C_NUMBER);
+  pct_adj_ocean = count_ocean_near_tile(ptile, C_ADJACENT, C_PERCENT);
+  pct_adj_river = count_special_near_tile(ptile, C_ADJACENT, C_PERCENT,
+                                          S_RIVER);
+
+  return (num_card_river == 1 && num_card_ocean == 0
+          && pct_adj_ocean < 20 && pct_adj_river < 35
+          /* The following expression helps with straightness,
+           * ocean avoidance, and reduces forking. */
+          && (pct_adj_river + pct_adj_ocean * 2) < myrand(25) + 25);
+}
+
+/**************************************************************************
+  Fill an island with rivers.
 **************************************************************************/
 static void fill_island_rivers(int coast, long int *bucket,
-			       const struct gen234_state *const pstate)
+                               const struct gen234_state *const pstate)
 {
-  int i, k, capac;
-  long int failsafe;
+  long int failsafe, capac, i, k;
+  struct tile *ptile;
 
-  if (*bucket <= 0 ) {
+  if (*bucket <= 0) {
     return;
   }
   capac = pstate->totalmass;
@@ -1510,30 +1548,27 @@ static void fill_island_rivers(int coast, long int *bucket,
   i++;
   *bucket -= i * capac;
 
+  /* generate 75% more rivers than generator 1 */
+  i = (i * 175) / 100;
+
   k = i;
-  failsafe = i * (pstate->s - pstate->n) * (pstate->e - pstate->w);
+  failsafe = i * (pstate->s - pstate->n) * (pstate->e - pstate->w) * 5;
   if (failsafe < 0) {
     failsafe = -failsafe;
   }
 
-  while (i > 0 && (failsafe--) > 0) {
-    struct tile *ptile = get_random_map_position_from_state(pstate);
-    if (tile_get_continent(ptile) == pstate->isleindex
-	&& not_placed(ptile)) {
+  while (i > 0 && failsafe-- > 0) {
+    ptile = get_random_map_position_from_state(pstate);
+    if (tile_get_continent(ptile) != pstate->isleindex
+        || tile_has_special(ptile, S_RIVER)) {
+      continue;
+    }
 
-      /* the first condition helps make terrain more contiguous,
-	 the second lets it avoid the coast: */
-      if ((i * 3 > k * 2 
-	   || count_special_near_tile(ptile, FALSE, TRUE, S_RIVER) > 0
-	   || myrand(100) < 50)
-	  && (!is_cardinally_adj_to_ocean(ptile) || myrand(100) < coast)) {
-	if (is_water_adjacent_to_tile(ptile)
-	    && count_ocean_near_tile(ptile, FALSE, TRUE) < 50
-            && count_special_near_tile(ptile, FALSE, TRUE, S_RIVER) < 35) {
-	  tile_set_special(ptile, S_RIVER);
-	  i--;
-	}
-      }
+    if ((island_river_mouth_suitability(ptile)
+         && (myrand(100) < coast || i == k))
+        || island_river_suitability(ptile)) {
+      tile_set_special(ptile, S_RIVER);
+      i--;
     }
   }
 }
diff --git a/common/map.h b/common/map.h
index 9bf6e71..f81da63 100644
--- a/common/map.h
+++ b/common/map.h
@@ -82,6 +82,12 @@ enum topo_flag {
   TF_HEX = 8
 };
 
+/* Parameters for terrain counting functions. */
+static const bool C_ADJACENT = FALSE;
+static const bool C_CARDINAL = TRUE;
+static const bool C_NUMBER = FALSE;
+static const bool C_PERCENT = TRUE;
+
 #define MAP_IS_ISOMETRIC (topo_has_flag(TF_ISO) || topo_has_flag(TF_HEX))
 
 #define CURRENT_TOPOLOGY (map.topology_id)
diff --git a/server/generator/mapgen.c b/server/generator/mapgen.c
index b36a183..3756a65 100644
--- a/server/generator/mapgen.c
+++ b/server/generator/mapgen.c
@@ -1526,15 +1526,53 @@ static void fill_island(int coast, long int *bucket,
 }
 
 /**************************************************************************
-  fill an island with rivers
+  Returns TRUE if ptile is suitable for a river mouth.
+**************************************************************************/
+static bool island_river_mouth_suitability(const struct tile *ptile)
+{
+  int num_card_ocean, pct_adj_ocean, num_adj_river;
+
+  num_card_ocean = count_ocean_near_tile(ptile, C_CARDINAL, C_NUMBER);
+  pct_adj_ocean = count_ocean_near_tile(ptile, C_ADJACENT, C_PERCENT);
+  num_adj_river = count_special_near_tile(ptile, C_ADJACENT, C_NUMBER,
+                                          S_RIVER);
+
+  return (num_card_ocean == 1 && pct_adj_ocean <= 35
+          && num_adj_river == 0);
+}
+
+/**************************************************************************
+  Returns TRUE if there is a river in a cardinal direction near the tile
+  and the tile is suitable for extending it.
+**************************************************************************/
+static bool island_river_suitability(const struct tile *ptile)
+{
+  int pct_adj_ocean, num_card_ocean, pct_adj_river, num_card_river;
+
+  num_card_river = count_special_near_tile(ptile, C_CARDINAL, C_NUMBER,
+                                           S_RIVER);
+  num_card_ocean = count_ocean_near_tile(ptile, C_CARDINAL, C_NUMBER);
+  pct_adj_ocean = count_ocean_near_tile(ptile, C_ADJACENT, C_PERCENT);
+  pct_adj_river = count_special_near_tile(ptile, C_ADJACENT, C_PERCENT,
+                                          S_RIVER);
+
+  return (num_card_river == 1 && num_card_ocean == 0
+          && pct_adj_ocean < 20 && pct_adj_river < 35
+          /* The following expression helps with straightness,
+           * ocean avoidance, and reduces forking. */
+          && (pct_adj_river + pct_adj_ocean * 2) < myrand(25) + 25);
+}
+
+/**************************************************************************
+  Fill an island with rivers.
 **************************************************************************/
 static void fill_island_rivers(int coast, long int *bucket,
-			       const struct gen234_state *const pstate)
+                               const struct gen234_state *const pstate)
 {
-  int i, k, capac;
-  long int failsafe;
+  long int failsafe, capac, i, k;
+  struct tile *ptile;
 
-  if (*bucket <= 0 ) {
+  if (*bucket <= 0) {
     return;
   }
   capac = pstate->totalmass;
@@ -1542,30 +1580,27 @@ static void fill_island_rivers(int coast, long int *bucket,
   i++;
   *bucket -= i * capac;
 
+  /* generate 75% more rivers than generator 1 */
+  i = (i * 175) / 100;
+
   k = i;
-  failsafe = i * (pstate->s - pstate->n) * (pstate->e - pstate->w);
+  failsafe = i * (pstate->s - pstate->n) * (pstate->e - pstate->w) * 5;
   if (failsafe < 0) {
     failsafe = -failsafe;
   }
 
-  while (i > 0 && (failsafe--) > 0) {
-    struct tile *ptile = get_random_map_position_from_state(pstate);
-    if (tile_continent(ptile) == pstate->isleindex
-	&& not_placed(ptile)) {
+  while (i > 0 && failsafe-- > 0) {
+    ptile = get_random_map_position_from_state(pstate);
+    if (tile_continent(ptile) != pstate->isleindex
+        || tile_has_special(ptile, S_RIVER)) {
+      continue;
+    }
 
-      /* the first condition helps make terrain more contiguous,
-	 the second lets it avoid the coast: */
-      if ((i * 3 > k * 2 
-	   || count_special_near_tile(ptile, FALSE, TRUE, S_RIVER) > 0
-	   || myrand(100) < 50)
-	  && (!is_cardinally_adj_to_ocean(ptile) || myrand(100) < coast)) {
-	if (is_water_adjacent_to_tile(ptile)
-	    && count_ocean_near_tile(ptile, FALSE, TRUE) < 50
-            && count_special_near_tile(ptile, FALSE, TRUE, S_RIVER) < 35) {
-	  tile_set_special(ptile, S_RIVER);
-	  i--;
-	}
-      }
+    if ((island_river_mouth_suitability(ptile)
+         && (myrand(100) < coast || i == k))
+        || island_river_suitability(ptile)) {
+      tile_set_special(ptile, S_RIVER);
+      i--;
     }
   }
 }
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to