2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2020, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure, Markus Armbruster
6 * Empire is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * See files README, COPYING and CREDITS in the root of the source
22 * tree for related information and legal notices. It is expected
23 * that future projects/authors will amend these files as needed.
27 * fairland.c: Create a nice, new world
29 * Known contributors to this file:
32 * Markus Armbruster, 2004-2020
40 * Place the capitals on the torus in such a way so as to maximize
41 * their distances from one another. This uses the perturbation
42 * technique of calculus of variations.
44 * 2. Grow start islands ("continents")
46 * For all continents, add the first sector at the capital's location,
47 * and the second right to it. These are the capital sectors. Then
48 * add one sector to each continent in turn, until they have the
51 * Growth uses weighted random sampling to pick one sector from the
52 * set of adjacent sea sectors that aren't too close to another
53 * continent. Growth operates in spiking mode with a chance given by
54 * the spike percentage. When "spiking", a sector's weight increases
55 * with number of adjacent sea sectors. This directs the growth away
56 * from land, resulting in spikes. When not spiking, the weight
57 * increases with the number of adjacent land sectors. This makes the
58 * island more rounded.
60 * If growing fails due to lack of room, start over. If it fails too
61 * many times, give up and terminate unsuccessfully.
63 * 3. Place and grow additional islands
65 * Each continent has a "sphere of influence": the set of sectors
66 * closer to it than to any other continent. Each island is entirely
67 * in one such sphere, and each sphere contains the same number of
68 * islands with the same sizes.
70 * First, split the specified number of island sectors per continent
71 * randomly into the island sizes. Sort by size so that larger
72 * islands are grown before smaller ones, to give the large ones the
73 * best chance to grow to their planned size.
75 * Then place one island's first sector into each sphere, using
76 * weighted random sampling with weights favoring sectors away from
77 * land and other spheres. Add one sector to each island in turn,
78 * until they have the intended size. Repeat until the specified
79 * number of islands has been grown.
81 * If placement fails due to lack of room, start over, just like for
84 * Growing works as for continents, except the minimum distance for
85 * additional islands applies, and growing simply stops when any of
86 * the islands being grown lacks the room to grow further. The number
87 * of sectors not grown carries over to the next island size.
89 * 4. Compute elevation
91 * First, use a simple random hill algorithm to assign raw elevations:
92 * initialize elevation to zero, then randomly raise circular hills on
93 * land / lower circular depressions at sea. Their size and height
94 * depends on the distance to the coast.
96 * Then, elevate islands one after the other.
98 * Set the capitals' elevation to a fixed value. Process the
99 * remaining sectors in order of increasing raw elevation, first
100 * non-mountains, then mountains. Non-mountain elevation starts at 1,
101 * and increases linearly to just below "high" elevation. Mountain
102 * elevation starts at "high" elevation, and increases linearly.
104 * This gives islands of the same size the same set of elevations.
105 * Larger islands get more and taller mountains.
107 * Finally, elevate sea: normalize the raw elevations to [-127:-1].
111 * Sector resources are simple functions of elevation. You can alter
112 * macros OIL_MAX, IRON_MIN, GOLD_MIN, FERT_MAX, and URAN_MIN to
127 #include "prototypes.h"
132 /* The following five numbers refer to elevation under which (in the case of
133 fertility or oil) or over which (in the case of iron, gold, and uranium)
134 sectors with that elevation will contain that resource. Elevation ranges
137 /* raise FERT_MAX for more fertility */
140 /* raise OIL_MAX for more oil */
143 /* lower IRON_MIN for more iron */
146 /* lower GOLD_MIN for more gold */
149 /* lower URAN_MIN for more uranium */
152 /* do not change these defines */
153 #define LANDMIN 1 /* plate altitude for normal land */
154 #define PLATMIN 36 /* plate altitude for plateau */
155 #define HIGHMIN 98 /* plate altitude for mountains */
157 static void qprint(const char * const fmt, ...)
158 ATTRIBUTE((format (printf, 1, 2)));
161 * Program arguments and options
163 static char *program_name;
164 static int nc, sc; /* number and size of continents */
165 static int ni, is; /* number and size of islands */
166 #define DEFAULT_SPIKE 10
167 static int sp = DEFAULT_SPIKE; /* spike percentage */
168 #define DEFAULT_MOUNTAIN 0
169 static int pm = DEFAULT_MOUNTAIN; /* mountain percentage */
170 #define DEFAULT_CONTDIST 2
171 static int di = DEFAULT_CONTDIST; /* min. distance between continents */
172 #define DEFAULT_ISLDIST 1
173 static int id = DEFAULT_ISLDIST; /* ... continents and islands */
174 /* don't let the islands crash into each other.
175 1 = don't merge, 0 = merge. */
176 static int DISTINCT_ISLANDS = 1;
178 #define DEFAULT_OUTFILE_NAME "newcap_script"
179 static const char *outfile = DEFAULT_OUTFILE_NAME;
181 #define STABLE_CYCLE 4 /* stability required for perterbed capitals */
182 #define DRIFT_BEFORE_CHECK ((WORLD_X + WORLD_Y)/2)
183 #define DRIFT_MAX ((WORLD_X + WORLD_Y)*2)
188 #define new_x(newx) (((newx) + WORLD_X) % WORLD_X)
189 #define new_y(newy) (((newy) + WORLD_Y) % WORLD_Y)
193 * isecs[i] is the size of the i-th island.
197 static int *capx, *capy; /* location of the nc capitals */
199 static int **own; /* owner of the sector. -1 means water */
202 * Adjacent land sectors
203 * adj_land[XYOFFSET(x, y)] bit d is set exactly when the sector next
204 * to x, y in direction d is land.
206 static unsigned char *adj_land;
210 * elev[XYOFFSET(x, y)] is x,y's elevation.
216 * Each island is surrounded by an exclusive zone where only it may
217 * grow. The width of the zone depends on minimum distances.
218 * While growing continents, it is @di sectors wide.
219 * While growing additional islands, it is @id sectors wide.
220 * DISTINCT_ISLANDS nullifies the exclusive zone then.
221 * xzone[XYOFFSET(x, y)] is -1 when the sector is in no exclusive
222 * zone, a (non-negative) island number when it is in that island's
223 * exclusive zone and no other, and -2 when it is in multiple
229 * Set of sectors seen already
230 * Increment @cur_seen to empty the set of sectors seen, set
231 * seen[XYOFFSET(x, y)] to @cur_seen to add x,y to the set.
233 static unsigned *seen;
234 static unsigned cur_seen;
237 * Closest continent and "distance"
238 * closest[XYOFFSET(x, y)] is the closest continent's number.
239 * distance[] is complicated; see init_spheres_of_influence() and
240 * init_distance_to_coast().
242 static natid *closest;
243 static unsigned short *distance;
246 * Queue for breadth-first search
248 static int *bfs_queue;
249 static int bfs_queue_head, bfs_queue_tail;
251 static int **sectx, **secty; /* the sectors for each continent */
253 #define NUMTRIES 10 /* keep trying to grow this many times */
255 static const char *numletter =
256 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
258 static void help(char *);
259 static void usage(void);
260 static void parse_args(int argc, char *argv[]);
261 static void allocate_memory(void);
262 static void init(void);
263 static int drift(void);
264 static int grow_continents(void);
265 static void create_elevations(void);
266 static void write_sects(void);
267 static void output(void);
268 static int write_newcap_script(void);
269 static int stable(int);
270 static void elevate_prep(void);
271 static void elevate_land(void);
272 static void elevate_sea(void);
274 static void print_vars(void);
275 static void fl_move(int);
276 static int grow_islands(void);
278 /* Debugging aids: */
279 void print_own_map(void);
280 void print_xzone_map(void);
281 void print_closest_map(void);
282 void print_distance_map(void);
283 void print_elev_map(void);
285 /****************************************************************************
287 ****************************************************************************/
290 main(int argc, char *argv[])
293 char *config_file = NULL;
295 unsigned rnd_seed = 0;
298 program_name = argv[0];
300 while ((opt = getopt(argc, argv, "e:hiqR:s:v")) != EOF) {
303 config_file = optarg;
306 DISTINCT_ISLANDS = 0;
312 rnd_seed = strtoul(optarg, NULL, 10);
322 printf("%s\n\n%s", version, legal);
331 rnd_seed = pick_seed();
334 if (emp_config(config_file) < 0)
338 parse_args(argc - optind, argv + optind);
343 qprint("\n #*# ...fairland rips open a rift in the datumplane... #*#\n\n");
344 qprint("seed is %u\n", rnd_seed);
349 qprint("\ntry #%d (out of %d)...\n", try + 1, NUMTRIES);
350 qprint("placing capitals...\n");
352 qprint("unstable drift\n");
353 qprint("growing continents...\n");
354 done = grow_continents();
357 qprint("growing islands:");
358 done = grow_islands();
359 } while (!done && ++try < NUMTRIES);
361 fprintf(stderr, "%s: world not large enough for this much land\n",
365 qprint("elevating land...\n");
368 qprint("writing to sectors file...\n");
369 if (!write_newcap_script())
371 if (chdir(gamedir)) {
372 fprintf(stderr, "%s: can't chdir to %s (%s)\n",
373 program_name, gamedir, strerror(errno));
376 if (!ef_open(EF_SECTOR, EFF_MEM | EFF_NOTIME))
379 if (!ef_close(EF_SECTOR))
383 qprint("\n\nA script for adding all the countries can be found in \"%s\".\n",
393 puts("Creating a planet with:\n");
394 printf("%d continents\n", nc);
395 printf("continent size: %d\n", sc);
396 printf("number of islands: %d\n", ni);
397 printf("average size of islands: %d\n", is);
398 printf("spike: %d%%\n", sp);
399 printf("%d%% of land is mountain (each continent will have %d mountains)\n",
400 pm, (pm * sc) / 100);
401 printf("minimum distance between continents: %d\n", di);
402 printf("minimum distance from islands to continents: %d\n", id);
403 printf("World dimensions: %dx%d\n", WORLD_X, WORLD_Y);
407 help(char *complaint)
410 fprintf(stderr, "%s: %s\n", program_name, complaint);
411 fprintf(stderr, "Try -h for help.\n");
417 printf("Usage: %s [OPTION]... NC SC [NI] [IS] [SP] [PM] [DI] [ID]\n"
418 " -e CONFIG-FILE configuration file\n"
420 " -i islands may merge\n"
422 " -R SEED seed for random number generator\n"
423 " -s SCRIPT name of script to create (default %s)\n"
424 " -h display this help and exit\n"
425 " -v display version information and exit\n"
426 " NC number of continents\n"
427 " SC continent size\n"
428 " NI number of islands (default NC)\n"
429 " IS average island size (default SC/2)\n"
430 " SP spike percentage: 0 = round, 100 = snake (default %d)\n"
431 " PM percentage of land that is mountain (default %d)\n"
432 " DI minimum distance between continents (default %d)\n"
433 " ID minimum distance from islands to continents (default %d)\n",
434 program_name, dflt_econfig, DEFAULT_OUTFILE_NAME,
435 DEFAULT_SPIKE, DEFAULT_MOUNTAIN, DEFAULT_CONTDIST, DEFAULT_ISLDIST);
439 parse_args(int argc, char *argv[])
441 int dist_max = mapdist(0, 0, WORLD_X / 2, WORLD_Y / 2);
444 help("missing arguments");
448 help("too many arguments");
453 fprintf(stderr, "%s: number of continents must be > 0\n",
460 fprintf(stderr, "%s: size of continents must be > 1\n",
471 fprintf(stderr, "%s: number of islands must be >= 0\n",
476 fprintf(stderr, "%s: number of islands must be a multiple of"
477 " the number of continents\n",
485 fprintf(stderr, "%s: size of islands must be > 0\n",
492 if (sp < 0 || sp > 100) {
494 "%s: spike percentage must be between 0 and 100\n",
501 if (pm < 0 || pm > 100) {
503 "%s: mountain percentage must be between 0 and 100\n",
511 fprintf(stderr, "%s: distance between continents must be >= 0\n",
516 fprintf(stderr, "%s: distance between continents too large\n",
525 "%s: distance from islands to continents must be >= 0\n",
531 "%s: distance from islands to continents too large\n",
537 /****************************************************************************
538 VARIABLE INITIALIZATION
539 ****************************************************************************/
542 allocate_memory(void)
546 capx = calloc(nc, sizeof(int));
547 capy = calloc(nc, sizeof(int));
548 own = calloc(WORLD_X, sizeof(int *));
549 adj_land = malloc(WORLD_SZ() * sizeof(*adj_land));
550 elev = calloc(WORLD_SZ(), sizeof(*elev));
551 xzone = malloc(WORLD_SZ() * sizeof(*xzone));
552 seen = calloc(WORLD_SZ(), sizeof(*seen));
553 closest = malloc(WORLD_SZ() * sizeof(*closest));
554 distance = malloc(WORLD_SZ() * sizeof(*distance));
555 bfs_queue = malloc(WORLD_SZ() * sizeof(*bfs_queue));
556 for (i = 0; i < WORLD_X; ++i) {
557 own[i] = calloc(WORLD_Y, sizeof(int));
559 sectx = calloc(nc + ni, sizeof(int *));
560 secty = calloc(nc + ni, sizeof(int *));
561 isecs = calloc(nc + ni, sizeof(int));
562 for (i = 0; i < nc; ++i) {
563 sectx[i] = calloc(sc, sizeof(int));
564 secty[i] = calloc(sc, sizeof(int));
566 for (i = nc; i < nc + ni; ++i) {
567 sectx[i] = calloc(is * 2, sizeof(int));
568 secty[i] = calloc(is * 2, sizeof(int));
578 for (i = 0; i < WORLD_X; ++i) {
579 for (j = 0; j < WORLD_Y; ++j) {
583 memset(adj_land, 0, WORLD_SZ() * sizeof(*adj_land));
586 /****************************************************************************
587 DRIFT THE CAPITALS UNTIL THEY ARE AS FAR AWAY FROM EACH OTHER AS POSSIBLE
588 ****************************************************************************/
591 * How isolated is capital @j at @newx,@newy?
592 * Return the distance to the closest other capital.
595 iso(int j, int newx, int newy)
600 for (i = 0; i < nc; ++i) {
603 md = mapdist(capx[i], capy[i], newx, newy);
613 * Return 1 for a stable drift, 0 for an unstable one.
620 for (i = 0; i < nc; i++) {
621 capy[i] = (2 * i) / WORLD_X;
622 capx[i] = (2 * i) % WORLD_X + capy[i] % 2;
623 if (capy[i] >= WORLD_Y) {
625 "%s: world not big enough for all the continents\n",
631 for (turns = 0; turns < DRIFT_MAX; ++turns) {
634 for (i = 0; i < nc; ++i)
641 * Has the drift stabilized?
642 * @turns is the number of turns so far.
647 static int mc[STABLE_CYCLE];
648 int i, isod, d = 0, stab = 1;
651 for (i = 0; i < STABLE_CYCLE; i++)
655 if (turns <= DRIFT_BEFORE_CHECK)
658 for (i = 0; i < nc; ++i) {
659 isod = iso(i, capx[i], capy[i]);
664 for (i = 0; i < STABLE_CYCLE; ++i)
668 mc[turns % STABLE_CYCLE] = d;
672 /* This routine does the actual drifting
678 int dir, i, newx, newy;
680 dir = DIR_L + roll0(6);
681 for (i = 0; i < 6; i++) {
684 newx = new_x(capx[j] + diroff[dir][0]);
685 newy = new_y(capy[j] + diroff[dir][1]);
687 if (iso(j, newx, newy) >= iso(j, capx[j], capy[j])) {
695 /****************************************************************************
697 ****************************************************************************/
700 is_coastal(int x, int y)
702 return adj_land[XYOFFSET(x, y)]
703 != (1u << (DIR_LAST + 1)) - (1u << DIR_FIRST);
706 struct hexagon_iter {
711 * Start iterating around @x0,@y0 at distance @d.
712 * Set *x,*y to coordinates of the first sector.
715 hexagon_first(struct hexagon_iter *iter, int x0, int y0, int n,
718 *x = new_x(x0 - 2 * n);
720 iter->dir = DIR_FIRST;
726 * Continue iteration started with hexagon_first().
727 * Set *x,*y to coordinates of the next sector.
728 * Return whether we're back at the first sector, i.e. iteration is
732 hexagon_next(struct hexagon_iter *iter, int *x, int *y)
734 *x = new_x(*x + diroff[iter->dir][0]);
735 *y = new_y(*y + diroff[iter->dir][1]);
737 if (iter->i == iter->n) {
741 return iter->dir <= DIR_LAST;
745 * Is @x,@y in no exclusive zone other than perhaps @c's?
748 xzone_ok(int c, int x, int y)
750 int off = XYOFFSET(x, y);
752 return xzone[off] == c || xzone[off] == -1;
756 * Add sectors within distance @dist of @x,@y to @c's exclusive zone.
759 xzone_around_sector(int c, int x, int y, int dist)
762 struct hexagon_iter hexit;
764 assert(xzone_ok(c, x, y));
766 xzone[XYOFFSET(x, y)] = c;
767 for (d = 1; d <= dist; d++) {
768 hexagon_first(&hexit, x, y, d, &x1, &y1);
770 off = XYOFFSET(x1, y1);
771 if (xzone[off] == -1)
773 else if (xzone[off] != c)
775 } while (hexagon_next(&hexit, &x1, &y1));
780 * Add sectors within distance @dist to island @c's exclusive zone.
783 xzone_around_island(int c, int dist)
787 for (i = 0; i < isecs[c]; i++)
788 xzone_around_sector(c, sectx[c][i], secty[c][i], dist);
792 * Initialize exclusive zones around @n islands.
799 for (i = 0; i < WORLD_SZ(); i++)
802 for (c = 0; c < n; c++)
803 xzone_around_island(c, id);
807 * Initialize breadth-first search.
814 for (i = 0; i < WORLD_SZ(); i++) {
816 distance[i] = USHRT_MAX;
819 bfs_queue_head = bfs_queue_tail = 0;
823 * Add sector @x,@y to the BFS queue.
824 * It's closest to @c, with distance @dist.
827 bfs_enqueue(int c, int x, int y, int dist)
829 int off = XYOFFSET(x, y);
831 assert(dist < distance[off]);
833 distance[off] = dist;
834 bfs_queue[bfs_queue_tail] = off;
836 if (bfs_queue_tail >= WORLD_SZ())
838 assert(bfs_queue_tail != bfs_queue_head);
842 * Search breadth-first until the queue is empty.
847 int off, dist, i, noff, nx, ny;
850 while (bfs_queue_head != bfs_queue_tail) {
851 off = bfs_queue[bfs_queue_head];
853 if (bfs_queue_head >= WORLD_SZ())
855 dist = distance[off] + 1;
856 sctoff2xy(&x, &y, off);
857 for (i = DIR_FIRST; i <= DIR_LAST; i++) {
858 nx = new_x(x + diroff[i][0]);
859 ny = new_y(y + diroff[i][1]);
860 noff = XYOFFSET(nx, ny);
861 if (dist < distance[noff]) {
862 bfs_enqueue(closest[off], nx, ny, dist);
863 } else if (distance[noff] == dist) {
864 if (closest[off] != closest[noff])
865 closest[noff] = (natid)-1;
867 assert(distance[noff] < dist);
873 * Add island @c's coastal sectors to the BFS queue, with distance 0.
876 bfs_enqueue_island(int c)
880 for (i = 0; i < isecs[c]; i++) {
881 if (is_coastal(sectx[c][i], secty[c][i]))
882 bfs_enqueue(c, sectx[c][i], secty[c][i], 0);
887 * Enqueue spheres of influence borders for breadth-first search.
890 bfs_enqueue_border(void)
892 int x, y, off, dir, nx, ny, noff;
894 for (y = 0; y < WORLD_Y; y++) {
895 for (x = y % 2; x < WORLD_X; x += 2) {
896 off = XYOFFSET(x, y);
897 if (distance[off] <= id + 1)
899 if (closest[off] == (natid)-1)
901 for (dir = DIR_FIRST; dir <= DIR_LAST; dir++) {
902 nx = new_x(x + diroff[dir][0]);
903 ny = new_y(y + diroff[dir][1]);
904 noff = XYOFFSET(nx, ny);
905 if (closest[noff] != closest[off]) {
906 bfs_enqueue(closest[off], x, y, id + 1);
915 * Compute spheres of influence
916 * A continent's sphere of influence is the set of sectors closer to
917 * it than to any other continent.
918 * Set closest[XYOFFSET(x, y)] to the closest continent's number,
919 * -1 if no single continent is closest.
920 * Set distance[XYOFFSET(x, y)] to the minimum of the distance to the
921 * closest coastal land sector and the distance to just outside the
922 * sphere of influence plus @id. For sea sectors within a continent's
923 * sphere of influence, distance[off] - id is the distance to the
924 * border of the area where additional islands can be placed.
927 init_spheres_of_influence(void)
932 for (c = 0; c < nc; c++)
933 bfs_enqueue_island(c);
935 bfs_enqueue_border();
940 * Precompute distance to coast
941 * Set distance[XYOFFSET(x, y)] to the distance to the closest coastal
943 * Set closest[XYOFFSET(x, y)] to the closest continent's number,
944 * -1 if no single continent is closest.
947 init_distance_to_coast(void)
952 for (c = 0; c < nc + ni; c++)
953 bfs_enqueue_island(c);
958 * Is @x,@y in the same sphere of influence as island @c?
959 * Always true when @c is a continent.
962 is_in_sphere(int c, int x, int y)
964 return c < nc || closest[XYOFFSET(x, y)] == c % nc;
968 * Can island @c grow at @x,@y?
971 can_grow_at(int c, int x, int y)
973 return own[x][y] == -1 && xzone_ok(c, x, y) && is_in_sphere(c, x, y);
977 adj_land_update(int x, int y)
979 int is_land = own[x][y] != -1;
980 int dir, nx, ny, noff;
982 for (dir = DIR_FIRST; dir <= DIR_LAST; dir++) {
983 nx = new_x(x + diroff[dir][0]);
984 ny = new_y(y + diroff[dir][1]);
985 noff = XYOFFSET(nx, ny);
987 adj_land[noff] |= 1u << DIR_BACK(dir);
989 adj_land[noff] &= ~(1u << DIR_BACK(dir));
994 add_sector(int c, int x, int y)
996 assert(own[x][y] == -1);
997 xzone_around_sector(c, x, y, c < nc ? di : DISTINCT_ISLANDS ? id : 0);
998 sectx[c][isecs[c]] = x;
999 secty[c][isecs[c]] = y;
1002 adj_land_update(x, y);
1006 grow_weight(int c, int x, int y, int spike)
1011 * #Land neighbors is #bits set in adj_land[].
1012 * Count them Brian Kernighan's way.
1015 for (b = adj_land[XYOFFSET(x, y)]; b; b &= b - 1)
1017 assert(n > 0 && n < 7);
1020 return (6 - n) * (6 - n);
1026 grow_one_sector(int c)
1028 int spike = roll0(100) < sp;
1029 int wsum, newx, newy, i, x, y, off, dir, nx, ny, noff, w;
1031 assert(cur_seen < UINT_MAX);
1036 for (i = 0; i < isecs[c]; i++) {
1039 off = XYOFFSET(x, y);
1041 for (dir = DIR_FIRST; dir <= DIR_LAST; dir++) {
1042 if (adj_land[off] & (1u << dir))
1044 nx = new_x(x + diroff[dir][0]);
1045 ny = new_y(y + diroff[dir][1]);
1046 noff = XYOFFSET(nx, ny);
1047 if (seen[noff] == cur_seen)
1049 assert(seen[noff] < cur_seen);
1050 seen[noff] = cur_seen;
1051 if (!can_grow_at(c, nx, ny))
1053 w = grow_weight(c, nx, ny, spike);
1054 assert(wsum < INT_MAX - w);
1056 if (roll0(wsum) < w) {
1066 add_sector(c, newx, newy);
1071 * Grow the continents.
1072 * Return 1 on success, 0 on error.
1075 grow_continents(void)
1082 for (c = 0; c < nc; ++c) {
1084 if (!can_grow_at(c, capx[c], capy[c])
1085 || !can_grow_at(c, new_x(capx[c] + 2), capy[c])) {
1089 add_sector(c, capx[c], capy[c]);
1090 add_sector(c, new_x(capx[c] + 2), capy[c]);
1094 qprint("No room for continents\n");
1098 for (secs = 2; secs < sc && done; secs++) {
1099 for (c = 0; c < nc; ++c) {
1100 if (!grow_one_sector(c))
1106 qprint("Only managed to grow %d out of %d sectors.\n",
1111 /****************************************************************************
1113 ****************************************************************************/
1116 * Place additional island @c's first sector.
1117 * Return 1 on success, 0 on error.
1120 place_island(int c, int isiz)
1122 int n, x, y, d, w, newx, newy;
1126 for (y = 0; y < WORLD_Y; y++) {
1127 for (x = y % 2; x < WORLD_X; x += 2) {
1128 if (can_grow_at(c, x, y)) {
1129 d = distance[XYOFFSET(x, y)];
1131 w = (d - id) * (d - id);
1132 n += MIN(w, (isiz + 2) / 3);
1142 add_sector(c, newx, newy);
1147 int_cmp(const void *a, const void *b)
1149 return *(int *)b - *(int *)a;
1156 int *isiz = malloc(n * sizeof(*isiz));
1161 for (i = 1; i < n; i++) {
1164 isiz[i] = is + r1 - r0;
1168 qsort(isiz, n, sizeof(*isiz), int_cmp);
1173 * Grow the additional islands.
1174 * Return 1 on success, 0 on error.
1179 int *island_size = size_islands();
1180 int xzone_valid = 0;
1182 int i, j, c, done, secs, isiz, x, y;
1184 init_spheres_of_influence();
1186 for (i = 0; i < ni / nc; i++) {
1192 carry += island_size[i];
1193 isiz = MIN(2 * is, carry);
1195 for (j = 0; j < nc; j++) {
1197 if (!place_island(c + j, isiz)) {
1198 qprint("\nNo room for island #%d\n", c - nc + j + 1);
1205 for (secs = 1; secs < isiz && done; secs++) {
1206 for (j = 0; j < nc; j++) {
1207 if (!grow_one_sector(c + j))
1214 for (j = 0; j < nc; j++) {
1215 if (isecs[c + j] != secs) {
1217 assert(isecs[c + j] == secs);
1218 x = sectx[c + j][secs];
1219 y = secty[c + j][secs];
1221 adj_land_update(x, y);
1227 for (j = 0; j < nc; j++)
1228 qprint(" %d(%d)", c - nc + j + 1, isecs[c + j]);
1237 qprint("Only managed to grow %d out of %d island sectors.\n",
1238 is * ni - carry * nc, is * ni);
1243 /****************************************************************************
1245 ****************************************************************************/
1247 create_elevations(void)
1255 elev_cmp(const void *p, const void *q)
1259 int delev = elev[a] - elev[b];
1261 return delev ? delev : a - b;
1267 int n = WORLD_SZ() * 8;
1268 int off0, r, sign, elevation, d, x1, y1, off1;
1270 struct hexagon_iter hexit;
1272 init_distance_to_coast();
1275 off0 = roll0(WORLD_SZ());
1276 sctoff2xy(&x0, &y0, off0);
1277 if (own[x0][y0] == -1) {
1278 r = roll(MIN(3, distance[off0]));
1281 r = roll(MIN(3, distance[off0]) + 1);
1284 elevation = elev[off0] + sign * r * r;
1285 elev[off0] = LIMIT_TO(elevation, SHRT_MIN, SHRT_MAX);
1287 for (d = 1; d < r; d++) {
1288 hexagon_first(&hexit, x0, y0, d, &x1, &y1);
1290 off1 = XYOFFSET(x1, y1);
1291 elevation = elev[off1] + sign * (r * r - d * d);
1292 elev[off1] = LIMIT_TO(elevation, SHRT_MIN, SHRT_MAX);
1294 } while (hexagon_next(&hexit, &x1, &y1));
1302 int *off = malloc(MAX(sc, is * 2) * sizeof(*off));
1303 int max_nm = (pm * MAX(sc, is * 2)) / 100;
1304 int c, nm, i0, n, i;
1305 double elevation, delta;
1307 for (c = 0; c < nc + ni; c++) {
1308 nm = (pm * isecs[c]) / 100;
1309 i0 = c < nc ? 2 : 0;
1311 for (i = 0; i < i0; i++)
1312 elev[XYOFFSET(sectx[c][i], secty[c][i])] = PLATMIN;
1313 for (i = 0; i < n; i++)
1314 off[i] = XYOFFSET(sectx[c][i0 + i], secty[c][i0 + i]);
1315 qsort(off, n, sizeof(*off), elev_cmp);
1316 delta = (double)(HIGHMIN - LANDMIN - 1) / (n - nm - 1);
1317 elevation = LANDMIN;
1318 for (i = 0; i < n - nm; i++) {
1319 elev[off[i]] = (int)(elevation + 0.5);
1322 elevation = HIGHMIN;
1323 delta = (127.0 - HIGHMIN) / max_nm;
1324 for (; i < n; i++) {
1326 elev[off[i]] = (int)(elevation + 0.5);
1339 for (i = 0; i < WORLD_SZ(); i++) {
1344 for (i = 0; i < WORLD_SZ(); i++) {
1346 elev[i] = -1 - 126 * elev[i] / min;
1351 elev_to_sct_type(int elevation)
1353 if (elevation < LANDMIN)
1355 if (elevation < HIGHMIN)
1360 /****************************************************************************
1362 ****************************************************************************/
1369 fert = LANDMIN - e + 40;
1370 else if (e < FERT_MAX)
1371 fert = (120 * (FERT_MAX - e)) / (FERT_MAX - LANDMIN);
1382 oil = (LANDMIN - e) * 2;
1383 else if (e <= OIL_MAX)
1384 oil = (120 * (OIL_MAX - e + 1)) / (OIL_MAX - LANDMIN + 1);
1394 if (e >= IRON_MIN && e < HIGHMIN)
1395 iron = (120 * (e - IRON_MIN + 1)) / (HIGHMIN - IRON_MIN);
1405 if (e >= GOLD_MIN) {
1407 gold = (80 * (e - GOLD_MIN + 1)) / (HIGHMIN - GOLD_MIN);
1409 gold = 80 + 5 * (e - HIGHMIN) / (127 - HIGHMIN);
1420 if (e >= URAN_MIN && e < HIGHMIN)
1421 uran = (120 * (e - URAN_MIN + 1)) / (HIGHMIN - URAN_MIN);
1428 add_resources(struct sctstr *sct)
1430 sct->sct_fertil = set_fert(sct->sct_elev);
1431 sct->sct_oil = set_oil(sct->sct_elev);
1432 sct->sct_min = set_iron(sct->sct_elev);
1433 sct->sct_gmin = set_gold(sct->sct_elev);
1434 sct->sct_uran = set_uran(sct->sct_elev);
1437 /****************************************************************************
1438 DESIGNATE THE SECTORS
1439 ****************************************************************************/
1447 for (y = 0; y < WORLD_Y; y++) {
1448 for (x = y % 2; x < WORLD_X; x += 2) {
1449 sct = getsectp(x, y);
1450 sct->sct_elev = elev[sct->sct_uid];
1451 sct->sct_type = elev_to_sct_type(sct->sct_elev);
1452 sct->sct_newtype = sct->sct_type;
1453 sct->sct_dterr = own[sct->sct_x][y] + 1;
1454 sct->sct_coastal = is_coastal(sct->sct_x, sct->sct_y);
1460 /****************************************************************************
1461 PRINT A PICTURE OF THE MAP TO YOUR SCREEN
1462 ****************************************************************************/
1466 int sx, sy, x, y, off, c, type;
1469 for (sy = -WORLD_Y / 2; sy < WORLD_Y / 2; sy++) {
1474 for (sx = -WORLD_X / 2 + y % 2; sx < WORLD_X / 2; sx += 2) {
1476 off = XYOFFSET(x, y);
1478 type = elev_to_sct_type(elev[off]);
1479 if (type == SCT_WATER)
1481 else if (type == SCT_MOUNT)
1486 assert(0 <= c && c < nc);
1487 if ((x == capx[c] || x == new_x(capx[c] + 2))
1489 printf("%c ", numletter[c % 62]);
1499 * Print a map to help visualize own[][].
1500 * This is for debugging.
1507 for (sy = -WORLD_Y / 2; sy < WORLD_Y / 2; sy++) {
1510 for (sx = -WORLD_X / 2; sx < WORLD_X / 2; sx++) {
1514 else if (own[x][y] == -1)
1517 putchar(numletter[own[x][y] % 62]);
1524 * Print a map to help visualize elev[].
1525 * This is for debugging. It expects the terminal to understand
1526 * 24-bit color escape sequences \e[48;2;$red;$green;$blue;m.
1529 print_elev_map(void)
1531 int sx, sy, x, y, off, sat;
1533 for (sy = -WORLD_Y / 2; sy < WORLD_Y / 2; sy++) {
1536 for (sx = -WORLD_X / 2; sx < WORLD_X / 2; sx++) {
1538 off = XYOFFSET(x, y);
1541 else if (!elev[off])
1543 else if (elev[off] < 0) {
1544 sat = 256 + elev[off] * 2;
1545 printf("\033[48;2;%d;%d;%dm \033[0m", sat, sat, 255);
1546 } else if (elev[off] < HIGHMIN / 2) {
1547 sat = (HIGHMIN / 2 - elev[off]) * 4;
1548 printf("\033[48;2;%d;%d;%dm \033[0m", sat, 255, sat);
1549 } else if (elev[off] < HIGHMIN) {
1550 sat = 128 + (HIGHMIN - elev[off]) * 2;
1551 printf("\033[48;2;%d;%d;%dm \033[0m", sat, sat / 2, sat / 4);
1553 sat = 128 + (elev[off] - HIGHMIN) * 2;
1554 printf("\033[48;2;%d;%d;%dm^\033[0m", sat, sat, sat);
1562 * Print a map to help visualize xzone[].
1563 * This is for debugging.
1566 print_xzone_map(void)
1568 int sx, sy, x, y, off;
1570 for (sy = -WORLD_Y / 2; sy < WORLD_Y / 2; sy++) {
1573 for (sx = -WORLD_X / 2; sx < WORLD_X / 2; sx++) {
1575 off = XYOFFSET(x, y);
1578 else if (own[x][y] >= 0)
1580 else if (xzone[off] >= 0)
1581 putchar(numletter[xzone[off] % 62]);
1583 assert(own[x][y] == -1);
1584 putchar(xzone[off] == -1 ? '.' : '!');
1592 * Print a map to help visualize closest[].
1593 * This is for debugging.
1596 print_closest_map(void)
1598 int sx, sy, x, y, off;
1600 for (sy = -WORLD_Y / 2; sy < WORLD_Y / 2; sy++) {
1603 for (sx = -WORLD_X / 2; sx < WORLD_X / 2; sx++) {
1605 off = XYOFFSET(x, y);
1608 else if (closest[off] == (natid)-1)
1610 else if (!distance[off]) {
1611 assert(closest[off] == own[x][y]);
1614 putchar(numletter[closest[off] % 62]);
1622 print_distance_map(void)
1624 int sx, sy, x, y, off;
1626 for (sy = -WORLD_Y / 2; sy < WORLD_Y / 2; sy++) {
1629 for (sx = -WORLD_X / 2; sx < WORLD_X / 2; sx++) {
1631 off = XYOFFSET(x, y);
1634 else if (closest[off] == (natid)-1)
1636 else if (!distance[off]) {
1637 assert(closest[off] == own[x][y]);
1640 putchar(numletter[distance[off] % 62]);
1648 /***************************************************************************
1649 WRITE A SCRIPT FOR PLACING CAPITALS
1650 ****************************************************************************/
1652 write_newcap_script(void)
1655 FILE *script = fopen(outfile, "w");
1658 fprintf(stderr, "%s: unable to write to %s (%s)\n",
1659 program_name, outfile, strerror(errno));
1663 for (c = 0; c < nc; ++c) {
1664 fprintf(script, "add %d %d %d p\n", c + 1, c + 1, c + 1);
1665 fprintf(script, "newcap %d %d,%d\n", c + 1, capx[c], capy[c]);
1667 fprintf(script, "add %d visitor visitor v\n", c + 1);
1673 qprint(const char *const fmt, ...)
1679 vfprintf(stdout, fmt, ap);