[Freeciv-Dev] (PR#10308) PATCH: New startpos option and rational control
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: |
undisclosed-recipients: ; |
Subject: |
[Freeciv-Dev] (PR#10308) PATCH: New startpos option and rational control of generators |
From: |
"Marcelo Burda" <mburda@xxxxxxxxx> |
Date: |
Sat, 2 Oct 2004 14:21:32 -0700 |
Reply-to: |
rt@xxxxxxxxxxx |
<URL: http://rt.freeciv.org/Ticket/Display.html?id=10308 >
FINAL VERSION (expet if some one has comments)
LAST CHANGES:
fix texts
rm all unneeded all to assign_continent_numbers
extend assign_continent_numbers(bool skip_unsafe) where TER_UNSAFE
tiles are not assigned to any ocean or continents, used by start_pos
this way to avoid bad placing start pos when separatepoles is off.
Marcelo
? server/.kdbgrc.civserver
Index: common/map.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/map.c,v
retrieving revision 1.199
diff -u -r1.199 map.c
--- common/map.c 1 Oct 2004 17:53:02 -0000 1.199
+++ common/map.c 2 Oct 2004 21:16:38 -0000
@@ -196,6 +196,7 @@
map.wetness = MAP_DEFAULT_WETNESS;
map.steepness = MAP_DEFAULT_STEEPNESS;
map.generator = MAP_DEFAULT_GENERATOR;
+ map.startpos = MAP_DEFAULT_STARTPOS;
map.tinyisles = MAP_DEFAULT_TINYISLES;
map.separatepoles = MAP_DEFAULT_SEPARATE_POLES;
map.alltemperate = MAP_DEFAULT_ALLTEMPERATE;
Index: common/map.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/map.h,v
retrieving revision 1.219
diff -u -r1.219 map.h
--- common/map.h 1 Oct 2004 17:53:02 -0000 1.219
+++ common/map.h 2 Oct 2004 21:16:38 -0000
@@ -172,6 +172,7 @@
int huts;
int landpercent;
int generator;
+ int startpos;
bool tinyisles;
bool separatepoles;
bool alltemperate;
@@ -651,7 +652,11 @@
#define MAP_DEFAULT_GENERATOR 1
#define MAP_MIN_GENERATOR 1
-#define MAP_MAX_GENERATOR 5
+#define MAP_MAX_GENERATOR 3
+
+#define MAP_DEFAULT_STARTPOS 0
+#define MAP_MIN_STARTPOS 0
+#define MAP_MAX_STARTPOS 4
#define MAP_DEFAULT_TINYISLES FALSE
#define MAP_MIN_TINYISLES FALSE
Index: server/maphand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/maphand.c,v
retrieving revision 1.149
diff -u -r1.149 maphand.c
--- server/maphand.c 29 Sep 2004 02:24:24 -0000 1.149
+++ server/maphand.c 2 Oct 2004 21:16:39 -0000
@@ -57,11 +57,16 @@
is_land tells us whether we are assigning continent numbers or ocean
numbers.
**************************************************************************/
-static void assign_continent_flood(struct tile *ptile, bool is_land, int nr)
+static void assign_continent_flood(struct tile *ptile, const bool is_land,
+ const int nr,const bool skip_unsafe)
{
if (map_get_continent(ptile) != 0) {
return;
}
+
+ if (skip_unsafe && terrain_has_flag(map_get_terrain(ptile), TER_UNSAFE)) {
+ return;
+ }
if (!XOR(is_land, is_ocean(map_get_terrain(ptile)))) {
return;
@@ -77,7 +82,7 @@
}
adjc_iterate(ptile, tile1) {
- assign_continent_flood(tile1, is_land, nr);
+ assign_continent_flood(tile1, is_land, nr, skip_unsafe);
} adjc_iterate_end;
}
@@ -117,10 +122,10 @@
Continents have numbers 1 to map.num_continents _inclusive_.
Oceans have (negative) numbers -1 to -map.num_oceans _inclusive_.
-
+
Also recalculate lake_surrounders[] arrays
**************************************************************************/
-void assign_continent_numbers(void)
+void assign_continent_numbers(const bool skip_unsafe)
{
int i;
@@ -140,18 +145,23 @@
/* Assign new numbers */
whole_map_iterate(ptile) {
+ const Terrain_type_id ter = map_get_terrain(ptile);
+
if (map_get_continent(ptile) != 0) {
/* Already assigned. */
continue;
}
- if (!is_ocean(map_get_terrain(ptile))) {
- map.num_continents++;
- assert(map.num_continents < MAP_NCONT);
- assign_continent_flood(ptile, TRUE, map.num_continents);
- } else {
- map.num_oceans++;
- assert(map.num_oceans < MAP_NCONT);
- assign_continent_flood(ptile, FALSE, -map.num_oceans);
+
+ if (!skip_unsafe || !terrain_has_flag(ter, TER_UNSAFE)) {
+ if (!is_ocean(ter)) {
+ map.num_continents++;
+ assert(map.num_continents < MAP_NCONT);
+ assign_continent_flood(ptile, TRUE, map.num_continents, skip_unsafe);
+ } else {
+ map.num_oceans++;
+ assert(map.num_oceans < MAP_NCONT);
+ assign_continent_flood(ptile, FALSE, -map.num_oceans, skip_unsafe);
+ }
}
} whole_map_iterate_end;
@@ -1463,7 +1473,7 @@
}
if (change_type != OLC_NONE) {
- assign_continent_numbers();
+ assign_continent_numbers(FALSE);
allot_island_improvs();
/* New continent numbers for all tiles to all players */
Index: server/maphand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/maphand.h,v
retrieving revision 1.48
diff -u -r1.48 maphand.h
--- server/maphand.h 29 Sep 2004 02:24:24 -0000 1.48
+++ server/maphand.h 2 Oct 2004 21:16:40 -0000
@@ -52,7 +52,7 @@
/* The maximum number of continents and oceans. */
#define MAP_NCONT 300
-void assign_continent_numbers(void);
+void assign_continent_numbers(const bool skip_unsafe);
void global_warming(int effect);
void nuclear_winter(int effect);
@@ -106,4 +106,5 @@
Terrain_type_id oldter);
int get_continent_size(Continent_id id);
int get_ocean_size(Continent_id id);
+
#endif /* FC__MAPHAND_H */
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.196
diff -u -r1.196 savegame.c
--- server/savegame.c 29 Sep 2004 02:24:24 -0000 1.196
+++ server/savegame.c 2 Oct 2004 21:16:41 -0000
@@ -384,8 +384,6 @@
secfile_lookup_str(file, "map.t%03d", line),
ptile->terrain = char2terrain(ch));
- assign_continent_numbers();
-
whole_map_iterate(ptile) {
ptile->spec_sprite = secfile_lookup_str_default(file, NULL,
"map.spec_sprite_%d_%d",
Index: server/settings.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settings.c,v
retrieving revision 1.5
diff -u -r1.5 settings.c
--- server/settings.c 20 Sep 2004 16:42:31 -0000 1.5
+++ server/settings.c 2 Oct 2004 21:16:42 -0000
@@ -259,21 +259,27 @@
GEN_INT("generator", map.generator,
SSET_MAP_GEN, SSET_GEOLOGY, SSET_VITAL, SSET_TO_CLIENT,
N_("Method used to generate map"),
- N_("1 = standard, with random continents;\n\n"
- "2 = equally sized large islands with one player each, and "
- "twice that many smaller islands;\n\n"
- "3 = equally sized large islands with one player each, and "
- "a number of other islands of similar size;\n\n"
- "4 = equally sized large islands with two players on every "
- "island (or one with three players for an odd number of "
- "players), and additional smaller islands;\n\n"
- "5 = one or more large earthlike continents with some "
- "scatter.\n\n"
- "Note: values 2,3 and 4 generate \"fairer\" (but more boring) "
- "maps.\n"
- "(Zero indicates a scenario map.)"), NULL,
+ N_("1 = Full random height map based generator [4]\n"
+ "2 = Pseudo-fractal height map based generator [3]\n"
+ "3 = Islands based generator [1]\n"
+ "(Zero indicates a scenario map.)\n"
+ "Notes: generator 3 generate fairer (but more boring) maps.\n"
+ "numbers in [] are default value for startpos"
+ ), NULL,
MAP_MIN_GENERATOR, MAP_MAX_GENERATOR, MAP_DEFAULT_GENERATOR)
+ GEN_INT("startpos", map.startpos,
+ SSET_MAP_GEN, SSET_GEOLOGY, SSET_VITAL, SSET_TO_CLIENT,
+ N_("Method used to choice starts pos"),
+ N_("0 = Developer choice, default of the generator\n"
+ "1 = try to place one player per continent\n"
+ "2 = try to place 2 players per continent\n"
+ "3 = try to place all players on some continent\n"
+ "4 = place number of players depending on size of continent\n"
+ "Note: generators try to do the right number of continents "
+ "for the choice of start pos and to the number of players"),
+ NULL, MAP_MIN_STARTPOS, MAP_MAX_STARTPOS, MAP_DEFAULT_STARTPOS)
+
GEN_BOOL("tinyisles", map.tinyisles,
SSET_MAP_GEN, SSET_GEOLOGY, SSET_RARE, SSET_TO_CLIENT,
N_("Presence of 1x1 islands"),
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.200
diff -u -r1.200 srv_main.c
--- server/srv_main.c 30 Sep 2004 12:31:26 -0000 1.200
+++ server/srv_main.c 2 Oct 2004 21:16:43 -0000
@@ -103,7 +103,6 @@
#include "citymap.h"
#include "mapgen.h"
-#include "startpos.h"
#include "srv_main.h"
@@ -1775,17 +1774,11 @@
}
/* if we have a tile map, and map.generator==0, call map_fractal_generate
- anyway, to make the specials and huts */
+ anyway, to make the specials, huts and assign_continent_numbers */
if (map_is_empty() || (map.generator == 0 && game.is_new_game)) {
map_fractal_generate(TRUE);
}
- /*
- * Don't assign continent numbers here. We have to do it later,
- * because generators 2-4 use their own continent numbering
- * in create_start_positions(). For other generators continent numbers
- * are already assigned.
- */
gamelog_map();
/* start the game */
@@ -1810,18 +1803,8 @@
* we don't want to change it. */
game.max_players = game.nplayers;
}
-
- /* we don't want random start positions in a scenario which already
- provides them. -- Gudy */
- if(map.num_start_positions == 0) {
- create_start_positions();
- }
-
}
- /* start positions are created, now we can do this safely */
- assign_continent_numbers();
-
/* Set up alliances based on team selections */
if (game.is_new_game) {
players_iterate(pplayer) {
Index: server/generator/height_map.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/height_map.c,v
retrieving revision 1.5
diff -u -r1.5 height_map.c
--- server/generator/height_map.c 29 Sep 2004 02:24:24 -0000 1.5
+++ server/generator/height_map.c 2 Oct 2004 21:16:43 -0000
@@ -157,7 +157,7 @@
All X and Y values used in this function are in native coordinates.
**************************************************************************/
-void make_pseudofractal1_hmap(void)
+void make_pseudofractal1_hmap(int extra_div)
{
const bool xnowrap = !topo_has_flag(TF_WRAPX);
const bool ynowrap = !topo_has_flag(TF_WRAPY);
@@ -166,8 +166,8 @@
* How many blocks should the x and y directions be divided into
* initially.
*/
- const int xdiv = 6;
- const int ydiv = 5;
+ const int xdiv = 5 + extra_div;
+ const int ydiv = 5 + extra_div;
int xdiv2 = xdiv + (xnowrap ? 1 : 0);
int ydiv2 = ydiv + (ynowrap ? 1 : 0);
Index: server/generator/height_map.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/height_map.h,v
retrieving revision 1.3
diff -u -r1.3 height_map.h
--- server/generator/height_map.h 29 Sep 2004 02:24:24 -0000 1.3
+++ server/generator/height_map.h 2 Oct 2004 21:16:43 -0000
@@ -37,6 +37,6 @@
void normalize_hmap_poles(void);
void renormalize_hmap_poles(void);
void make_random_hmap(int smooth);
-void make_pseudofractal1_hmap(void);
+void make_pseudofractal1_hmap(int div);
#endif /* FC__HEIGHT__MAP_H */
Index: server/generator/mapgen.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/mapgen.c,v
retrieving revision 1.12
diff -u -r1.12 mapgen.c
--- server/generator/mapgen.c 1 Oct 2004 17:53:02 -0000 1.12
+++ server/generator/mapgen.c 2 Oct 2004 21:16:44 -0000
@@ -31,9 +31,9 @@
#include "shared.h"
#include "srv_main.h"
-#include "mapgen.h"
#include "height_map.h"
+#include "mapgen.h"
#include "mapgen_topology.h"
#include "startpos.h"
#include "temperature_map.h"
@@ -300,7 +300,7 @@
****************************************************************************/
static void make_polar_land(void)
{
- assign_continent_numbers();
+ assign_continent_numbers(FALSE);
whole_map_iterate(ptile) {
if ((tmap_is(ptile, TT_FROZEN ) &&
ok_for_separate_poles(ptile))
@@ -945,8 +945,6 @@
destroy_placed_map();
make_rivers(); /* use a new placed_map. destroy older before call */
-
- assign_continent_numbers();
}
/**************************************************************************
@@ -1016,24 +1014,31 @@
adjust_terrain_param();
/* if one mapgenerator fails, it will choose another mapgenerator */
/* with a lower number to try again */
- if (map.generator == 5 ) {
- make_pseudofractal1_hmap();
- }
- if (map.generator == 4) {
- mapgenerator4();
- }
- if (map.generator == 3) {
- mapgenerator3();
+
+ if (map.generator == 3) {/* 2 or 3 player per isle*/
+ if (map.startpos == 2 || (map.startpos == 3) ) {
+ mapgenerator4();
+ }
+ if (map.startpos <= 1 ) { /* single player per isle */
+ mapgenerator3();
+ }
+ if (map.startpos == 4 ) { /* "variable" single player*/
+ mapgenerator2();
+ }
}
- if (map.generator == 2) {
- mapgenerator2();
+
+ if (map.generator == 2 ) {
+ make_pseudofractal1_hmap(1 +
+ ((map.startpos == 0 || map.startpos == 3) ? 0 : game.nplayers));
}
+
if (map.generator == 1 ) {
- make_random_hmap(1 + SQSIZE);
+ make_random_hmap(MAX(1, 1 + SQSIZE
+ - (map.startpos ? game.nplayers / 4: 0)));
}
/* if hmap only generator make anything else */
- if (map.generator == 1 || map.generator == 5) {
+ if (map.generator == 1 || map.generator == 2) {
make_land();
free(height_map);
height_map = NULL;
@@ -1041,8 +1046,6 @@
if (!map.tinyisles) {
remove_tiny_islands();
}
- } else {
- assign_continent_numbers();
}
if (!temperature_is_initialized()) {
@@ -1061,6 +1064,33 @@
/* restore previous random state: */
set_myrand_state(rstate);
destroy_tmap();
+
+ /* we don't want random start positions in a scenario which already
+ provides them. */
+ if (map.num_start_positions == 0) {
+ switch (map.generator) {
+ case 0:
+ case 1:
+ create_start_positions(map.startpos);
+ break;
+ case 2:
+ if (map.startpos == 0) {
+ create_start_positions(MT_ALL);
+ } else {
+ create_start_positions(map.startpos);
+ };
+ break;
+ case 3:
+ if (map.startpos <= 1 || (map.startpos == 4) ) {
+ create_start_positions(MT_SINGLE);
+ } else {
+ create_start_positions(MT_2or3);
+ };
+ break;
+ }
+ }
+
+ assign_continent_numbers(FALSE);
}
/**************************************************************************
@@ -1126,9 +1156,6 @@
number--;
map_set_special(ptile, S_HUT);
set_placed_near_pos(ptile, 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. */
}
}
}
@@ -1555,7 +1582,6 @@
if (i <= 0) {
return FALSE;
}
- islands[pstate->isleindex].starters = starters;
assert(starters >= 0);
freelog(LOG_VERBOSE, "island %i", pstate->isleindex);
@@ -1616,9 +1642,7 @@
**************************************************************************/
static void initworld(struct gen234_state *pstate)
{
- int i;
height_map = fc_malloc(sizeof(int) * map.ysize * map.xsize);
- islands = fc_malloc((MAP_NCONT+1)*sizeof(struct isledata));
create_placed_map(); /* land tiles which aren't placed yet */
create_tmap(FALSE);
@@ -1636,12 +1660,7 @@
/* Set poles numbers. After the map is generated continents will
* be renumbered. */
- assign_continent_numbers();
-
make_island(0, 0, pstate, 0);
- for(i = 0; i <= map.num_continents; i++ ) {
- islands[i].starters = 0;
- }
}
/* This variable is the Default Minimum Specific Island Size,
Index: server/generator/startpos.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/startpos.c,v
retrieving revision 1.3
diff -u -r1.3 startpos.c
--- server/generator/startpos.c 29 Sep 2004 02:24:24 -0000 1.3
+++ server/generator/startpos.c 2 Oct 2004 21:16:44 -0000
@@ -1,5 +1,5 @@
/**********************************************************************
- Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+ Freeciv - Copyright (C) 1996 - 2004 The Freeciv Project Team
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, or (at your option)
@@ -23,8 +23,17 @@
#include "mapgen_topology.h"
#include "startpos.h"
+#include "utilities.h"
-struct isledata *islands;
+typedef struct {
+ Continent_id id;
+ int size;
+ int goodies;
+ int starters;
+ int total;
+} islands_data_type;
+islands_data_type *islands;
+int *islands_index;
/****************************************************************************
Return an approximation of the goodness of a tile to a civilization.
@@ -54,8 +63,8 @@
map_set_special(ptile, S_ROAD);
map_mine_tile(ptile);
mine_bonus = (get_food_tile(ptile)
- + get_shields_tile(ptile)
- + get_trade_tile(ptile)) - value;
+ + get_shields_tile(ptile)
+ + get_trade_tile(ptile)) - value;
ptile->terrain = old_terrain;
ptile->special = old_special;
@@ -65,116 +74,10 @@
return value;
}
-/**************************************************************************
- Allocate islands array and fill in values.
- Note this is only used for map.generator <= 1 or >= 5, since others
- setups islands and starters explicitly.
-**************************************************************************/
-static void setup_isledata(void)
-{
- int starters = 0;
- int min, i;
-
- assert(map.num_continents > 0);
-
- /* allocate + 1 so can use continent number as index */
- islands = fc_calloc((map.num_continents + 1), sizeof(struct isledata));
-
- /* add up all the resources of the map */
- whole_map_iterate(ptile) {
- /* number of different continents seen from (x,y) */
- int seen_conts = 0;
- /* list of seen continents */
- Continent_id conts[CITY_TILES];
- int j;
-
- /* add tile's value to each continent that is within city
- * radius distance */
- map_city_radius_iterate(ptile, tile1) {
- /* (x1,y1) is possible location of a future city which will
- * be able to get benefit of the tile (x,y) */
- if (is_ocean(map_get_terrain(tile1))
- || map_colatitude(tile1) <= 2 * ICE_BASE_LEVEL) {
- /* Not land, or too cold. */
- continue;
- }
- for (j = 0; j < seen_conts; j++) {
- if (map_get_continent(tile1) == conts[j]) {
- /* Continent of (x1,y1) is already in the list */
- break;
- }
- }
- if (j >= seen_conts) {
- /* we have not seen this continent yet */
- assert(seen_conts < CITY_TILES);
- conts[seen_conts] = map_get_continent(tile1);
- seen_conts++;
- }
- } map_city_radius_iterate_end;
-
- /* Now actually add the tile's value to all these continents */
- for (j = 0; j < seen_conts; j++) {
- islands[conts[j]].goodies += get_tile_value(ptile);
- }
- } whole_map_iterate_end;
-
- /* now divide the number of desired starting positions among
- * the continents so that the minimum number of resources per starting
- * position is as large as possible */
-
- /* set minimum number of resources per starting position to be value of
- * the best continent */
- min = 0;
- for (i = 1; i <= map.num_continents; i++) {
- if (min < islands[i].goodies) {
- min = islands[i].goodies;
- }
- }
-
- /* place as many starting positions as possible with the current minumum
- * number of resources, if not enough are placed, decrease the minimum */
- while ((starters < game.nplayers) && (min > 0)) {
- int nextmin = 0;
-
- starters = 0;
- for (i = 1; i <= map.num_continents; i++) {
- int value = islands[i].goodies;
-
- starters += value / min;
- if (nextmin < (value / (value / min + 1))) {
- nextmin = value / (value / min + 1);
- }
- }
-
- freelog(LOG_VERBOSE,
- "%d starting positions allocated with\n"
- "at least %d resouces per starting position; \n",
- starters, min);
-
- assert(nextmin < min);
- /* This choice of next min guarantees that there will be at least
- * one more starter on one of the continents */
- min = nextmin;
- }
-
- if (min == 0) {
- freelog(LOG_VERBOSE,
- "If we continue some starting positions will have to have "
- "access to zero resources (as defined in get_tile_value). \n");
- freelog(LOG_FATAL,
- "Cannot create enough starting position and will abort.\n"
- "Please report this bug at " WEBSITE_URL);
- abort();
- } else {
- for (i = 1; i <= map.num_continents; i++) {
- islands[i].starters = islands[i].goodies / min;
- }
- }
-}
-
struct start_filter_data {
- int count; /* Number of existing start positions. */
- int dist; /* Minimum distance between starting positions. */
+ int count; /* Number of existing start positions. */
+ int min_value;
+ int *value;
};
/**************************************************************************
@@ -189,88 +92,258 @@
'nr' is the number of other start positions in
map.start_positions to check for too closeness.
**************************************************************************/
-static bool is_valid_start_pos(const struct tile *ptile, const void *dataptr)
+static bool is_valid_start_pos(const struct tile *ptile,
+ const void *dataptr)
{
- const struct start_filter_data *data = dataptr;
+ const struct start_filter_data *pdata = dataptr;
int i;
- Terrain_type_id t = map_get_terrain(ptile);
- if (is_ocean(map_get_terrain(ptile))) {
- return FALSE;
- }
+ /* Only start on certain terrain types. */
+ if (pdata->value[ptile->index] < pdata->min_value) {
+ return FALSE;
+ }
- if (islands[(int)map_get_continent(ptile)].starters == 0) {
+ if (islands[islands_index[(int) map_get_continent(ptile)]].starters == 0) {
return FALSE;
}
- /* Only start on certain terrain types. */
- if (!terrain_has_flag(t, TER_STARTER)) {
- return FALSE;
- }
-
/* Don't start on a hut. */
if (map_has_special(ptile, S_HUT)) {
return FALSE;
}
-
- /* Nobody will start on the poles since they aren't valid terrain. */
/* Don't start too close to someone else. */
- for (i = 0; i < data->count; i++) {
+ for (i = 0; i < pdata->count; i++) {
struct tile *tile1 = map.start_positions[i].tile;
- if (map_get_continent(ptile) == map_get_continent(tile1)
- && real_map_distance(ptile, tile1) < data->dist) {
+ if ((map_get_continent(ptile) == map_get_continent(tile1)
+ && (real_map_distance(ptile, tile1) * 1000 / pdata->min_value
+ <= (sqrt(get_continent_size(map_get_continent(ptile))
+ /
+ islands[islands_index
+ [(int) map_get_continent(ptile)]].total)
+ )))
+ || (real_map_distance(ptile, tile1) * 1000 / pdata->min_value < 5)) {
return FALSE;
}
}
-
return TRUE;
}
+/*************************************************************************
+ help function for qsort
+ *************************************************************************/
+static int compare_islands(const void *A, const void *B)
+{
+ return -(((islands_data_type *) A)->goodies
+ - ((islands_data_type *) B)->goodies);
+}
+
+/*********************************************
+ initialize with some 0 values, call malloc, etc
+********************************************/
+static void initialize_isle_data(void)
+{
+ int nr;
+ islands =
+ fc_malloc((map.num_continents + 1) * sizeof(islands_data_type));
+ islands_index = fc_malloc((map.num_continents + 1) * sizeof(int));
+
+ for (nr = 1; nr <= map.num_continents; nr++) {
+ islands[nr].id = nr;
+ islands[nr].size = get_continent_size(nr);
+ islands[nr].goodies = 0;
+ islands[nr].starters = 0;
+ islands[nr].total = 0;
+ }
+}
+
+/**************************************************************
+ help function for select good start tiles
+ **************************************************************/
+static bool filter(const struct tile *ptile, const void *data)
+{
+ return terrain_has_flag(map_get_terrain(ptile), TER_STARTER);
+}
+
/**************************************************************************
- where do the different races start on the map? well this function tries
+ where do the different nations start on the map? well this function tries
to spread them out on the different islands.
+ MT_SIGLE one player per isle
+ MT_2or3 2 player per isle if number of players is even
+ MT_ALL all player in single isle
+ MT_VARIABLE at last 2 player per isle
**************************************************************************/
-void create_start_positions(void)
+void create_start_positions(mode_type mode)
{
struct tile *ptile;
int k, sum;
struct start_filter_data data;
-
- if (!islands) {
- /* Isle data is already setup for generators 2, 3, and 4. */
- setup_isledata();
+ int tile_value_aux[MAX_MAP_INDEX], tile_value[MAX_MAP_INDEX];
+ int min_goodies_per_player = 2000;
+ int total_goodies = 0;
+
+ /* unsafe terrains separate continents for this task
+ else littles green isles near poles can be populated by
+ a civilization if pole touch a big one! */
+ assign_continent_numbers(TRUE);
+
+ /* create_start_positions not known what is the right default,
+ then use MT_VARIABLE */
+ if(mode == MT_DEFAULT) {
+ mode = MT_VARIABLE;
}
- data.dist = MIN(40, MIN(map.xsize / 2, map.ysize / 2));
+ /* get the tile value */
+ whole_map_iterate(ptile) {
+ tile_value_aux[ptile->index] = get_tile_value(ptile);
+ } whole_map_iterate_end;
+
+ /* select the best tiles */
+ whole_map_iterate(ptile) {
+ int this_tile_value = tile_value_aux[ptile->index];
+ int lcount = 0, bcount = 0;
+ map_city_radius_iterate(ptile, ptile1) {
+ if (this_tile_value > tile_value_aux[ptile1->index]) {
+ lcount++;
+ } else if (this_tile_value < tile_value_aux[ptile1->index]) {
+ bcount++;
+ }
+ }
+ map_city_radius_iterate_end;
+ if (lcount <= bcount) {
+ this_tile_value = 0;
+ }
+ tile_value[ptile->index] = 100 * this_tile_value;
+ } whole_map_iterate_end;
+ /* get a average value */
+ smooth_int_map(tile_value, TRUE);
+
+ initialize_isle_data();
+
+ /* oceans are not good for start, discard its */
+ whole_map_iterate(ptile) {
+ if (!filter(ptile, NULL)) {
+ tile_value[ptile->index] = 0;
+ } else {
+ islands[map_get_continent(ptile)].goodies
+ += tile_value[ptile->index];
+ total_goodies += tile_value[ptile->index];
+ }
+ } whole_map_iterate_end;
+
+ /* evaluate the best places on the map */
+ adjust_int_map_filtered(tile_value, 1000, NULL, filter);
+
+ /* best islands first */
+ qsort(islands + 1, (map.num_continents),
+ sizeof(islands_data_type), compare_islands);
+
+ /* some times we can't place start pos as wanted then choixe the best way */
+ if (mode == MT_SINGLE && map.num_continents < game.nplayers + 3) {
+ mode = MT_2or3;
+ }
+
+ if (mode == MT_2or3 && map.num_continents < game.nplayers / 2 + 4) {
+ mode = MT_VARIABLE;
+ }
+
+ if (mode == MT_ALL
+ && (islands[1].goodies < game.nplayers * min_goodies_per_player
+ || (islands[1].goodies < total_goodies * 0.5))) {
+ mode = MT_VARIABLE;
+ }
+
+ /* the variable way is the last posibility */
+ if (mode == MT_VARIABLE) {
+ min_goodies_per_player = total_goodies * 0.65 / game.nplayers;
+ }
+
+ {
+ int nr, to_place = game.nplayers, first = 1;
+ /* inizialize islands_index */
+ for (nr = 1; nr <= map.num_continents; nr++) {
+ islands_index[islands[nr].id] = nr;
+ }
+
+ /* sear for best first island for fairness */
+ if ((mode == MT_SINGLE) || (mode == MT_2or3)) {
+ float var_goodies, best = (float) HUGE_VAL;
+ int num_islands =
+ (mode == MT_SINGLE) ? game.nplayers : (game.nplayers / 2);
+
+ for (nr = 1; nr <= 1 + map.num_continents - num_islands; nr++) {
+ if (islands[nr + num_islands - 1].goodies
+ < min_goodies_per_player) {
+ break;
+ }
+ var_goodies
+ = (islands[nr].goodies - islands[nr + num_islands - 1].goodies)
+ / (islands[nr + num_islands - 1].goodies);
+
+ if (var_goodies < best * 0.9) {
+ best = var_goodies;
+ first = nr;
+ }
+ }
+ }
+
+ /* set starters per isle */
+ if (mode == MT_ALL) {
+ islands[1].starters = to_place;
+ islands[1].total = to_place;
+ to_place = 0;
+ }
+ for (nr = 1; nr <= map.num_continents; nr++) {
+
+ if (mode == MT_SINGLE && (to_place > 0) && (nr >= first)) {
+ islands[nr].starters = 1;
+ islands[nr].total = 1;
+ to_place--;
+ }
+ if (mode == MT_2or3 && (to_place > 0) && (nr >= first)) {
+ islands[nr].starters = 2 + (nr == 1 ? (game.nplayers % 2) : 0);
+ to_place -= islands[nr].total = islands[nr].starters;
+ }
+
+ if (mode == MT_VARIABLE && (to_place > 0)) {
+ islands[nr].starters = MAX(1, islands[nr].goodies
+ / min_goodies_per_player);
+ to_place -= islands[nr].total = islands[nr].starters;
+ }
+ }
+ }
data.count = 0;
+ data.value = tile_value;
+ data.min_value = 900;
sum = 0;
for (k = 1; k <= map.num_continents; k++) {
- sum += islands[k].starters;
- if (islands[k].starters != 0) {
+ sum += islands[islands_index[k]].starters;
+ if (islands[islands_index[k]].starters != 0) {
freelog(LOG_VERBOSE, "starters on isle %i", k);
}
}
assert(game.nplayers <= data.count + sum);
+ /* now search the best place and set start_positions */
map.start_positions = fc_realloc(map.start_positions,
game.nplayers
* sizeof(*map.start_positions));
while (data.count < game.nplayers) {
if ((ptile = rand_map_pos_filtered(&data, is_valid_start_pos))) {
- islands[(int)map_get_continent(ptile)].starters--;
+ islands[islands_index[(int) map_get_continent(ptile)]].starters--;
map.start_positions[data.count].tile = ptile;
map.start_positions[data.count].nation = NO_NATION_SELECTED;
- freelog(LOG_DEBUG, "Adding %d,%d as starting position %d.",
- ptile->x, ptile->y, data.count);
+ freelog(LOG_DEBUG,
+ "Adding %d,%d as starting position %d, %d goodies on islands.",
+ ptile->x, ptile->y, data.count,
+ islands[islands_index[(int) map_get_continent(ptile)]].goodies);
data.count++;
} else {
-
- data.dist--;
- if (data.dist == 0) {
+ data.min_value *= 0.9;
+ if (data.min_value <= 10) {
die(_("The server appears to have gotten into an infinite loop "
"in the allocation of starting positions, and will abort.\n"
"Maybe the numbers of players/ia is too much for this map.\n"
@@ -281,5 +354,7 @@
map.num_start_positions = game.nplayers;
free(islands);
+ free(islands_index);
islands = NULL;
+ islands_index = NULL;
}
Index: server/generator/startpos.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/startpos.h,v
retrieving revision 1.1
diff -u -r1.1 startpos.h
--- server/generator/startpos.h 16 Sep 2004 09:53:11 -0000 1.1
+++ server/generator/startpos.h 2 Oct 2004 21:16:44 -0000
@@ -13,12 +13,9 @@
#ifndef FC__STARTING_POSITIONS
#define FC__STARTING_POSITIONS
-void create_start_positions(void);
-/* This is manipulated directly by gen234 */
-struct isledata {
- int goodies;
- int starters;
-};
-extern struct isledata *islands;
+typedef enum {MT_DEFAULT = 0, MT_SINGLE, MT_2or3, MT_ALL, MT_VARIABLE}
+ mode_type;
+
+void create_start_positions(mode_type mode);
#endif
Index: server/generator/utilities.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/utilities.c,v
retrieving revision 1.8
diff -u -r1.8 utilities.c
--- server/generator/utilities.c 1 Oct 2004 17:53:02 -0000 1.8
+++ server/generator/utilities.c 2 Oct 2004 21:16:44 -0000
@@ -101,15 +101,18 @@
The lowest 20% of tiles will have values lower than 0.2 * int_map_max.
**************************************************************************/
-void adjust_int_map(int *int_map, int int_map_max)
+void adjust_int_map_filtered(int *int_map, int int_map_max, void *data,
+ bool (*filter)(const struct tile *ptile,
+ const void *data))
{
- int minval = *int_map, maxval = minval;
+ int minval = +(int)HUGE_VAL, maxval = -(int)HUGE_VAL, total = 0;
/* Determine minimum and maximum value. */
- whole_map_iterate(ptile) {
+ whole_map_iterate_filtered(ptile, data, filter) {
maxval = MAX(maxval, int_map[ptile->index]);
minval = MIN(minval, int_map[ptile->index]);
- } whole_map_iterate_end;
+ total++;
+ } whole_map_iterate_filtered_end;
{
int const size = 1 + maxval - minval;
@@ -120,21 +123,21 @@
/* Translate value so the minimum value is 0
and count the number of occurencies of all values to initialize the
frequencies[] */
- whole_map_iterate(ptile) {
+ whole_map_iterate_filtered(ptile, data, filter) {
int_map[ptile->index] = (int_map[ptile->index] - minval);
frequencies[int_map[ptile->index]]++;
- } whole_map_iterate_end;
+ } whole_map_iterate_filtered_end;
/* create the linearize function as "incremental" frequencies */
for(i = 0; i < size; i++) {
count += frequencies[i];
- frequencies[i] = (count * int_map_max) / MAX_MAP_INDEX;
+ frequencies[i] = (count * int_map_max) / total;
}
/* apply the linearize function */
- whole_map_iterate(ptile) {
+ whole_map_iterate_filtered(ptile, data, filter) {
int_map[ptile->index] = frequencies[int_map[ptile->index]];
- } whole_map_iterate_end;
+ } whole_map_iterate_filtered_end;
}
}
Index: server/generator/utilities.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/generator/utilities.h,v
retrieving revision 1.4
diff -u -r1.4 utilities.h
--- server/generator/utilities.h 1 Oct 2004 17:53:02 -0000 1.4
+++ server/generator/utilities.h 2 Oct 2004 21:16:44 -0000
@@ -56,11 +56,23 @@
#define iterate_axe_end \
} \
}
+#define whole_map_iterate_filtered(ptile, pdata, pfilter) \
+ whole_map_iterate(ptile) { \
+ if((pfilter) != NULL && !(pfilter)(ptile, (pdata))) { \
+ continue; \
+ }
+
+#define whole_map_iterate_filtered_end } whole_map_iterate_end
bool is_normal_nat_pos(int x, int y);
/* int maps tools */
-void adjust_int_map(int *int_map, int int_map_max);
+void adjust_int_map_filtered(int *int_map, int int_map_max, void *data,
+ bool (*filter)(const struct tile *ptile,
+ const void *data));
+#define adjust_int_map(int_map, int_map_max) \
+ adjust_int_map_filtered(int_map, int_map_max, (void *)NULL, \
+ (bool (*)(const struct tile *ptile, const void *data) )NULL)
void smooth_int_map(int *int_map, bool zeroes_at_edges);
/* placed_map tool*/
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Jason Short, 2004/10/01
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/01
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/01
- [Freeciv-Dev] (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/02
- [Freeciv-Dev] (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/02
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Per I. Mathisen, 2004/10/02
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/02
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/02
- [Freeciv-Dev] (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/02
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Per I. Mathisen, 2004/10/02
- [Freeciv-Dev] (PR#10308) PATCH: New startpos option and rational control of generators,
Marcelo Burda <=
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Jason Short, 2004/10/03
- [Freeciv-Dev] Re: (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/04
- [Freeciv-Dev] (PR#10308) PATCH: New startpos option and rational control of generators, Marcelo Burda, 2004/10/11
|
|