fairland: Try harder to deliver the requested amount of land

Planned island sizes are random with an expected value that matches
the average size requested by the user.  Can be off quite a bit when
the number of islands is small.  Also, actual island size can be
smaller than planned size when space is tight.

Instead of picking random island sizes independently, pick a random
split of their requested total size.

To reduce the probability of islands not growing to their planned
size, grow large islands before smaller ones.

To compensate for inability to grow, carry the difference over to the
next island size.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
Markus Armbruster 2020-08-11 17:58:23 +02:00
parent 08ca6ace12
commit 4fca4dfddd
10 changed files with 3940 additions and 3913 deletions

View file

@ -67,17 +67,22 @@
* in one such sphere, and each sphere contains the same number of
* islands with the same sizes.
*
* Pick an island size, and place one island's first sector into each
* sphere, randomly. Then add one sector to each island in turn,
* until they have the intended size. Repeat until the specified
* number of islands has been grown.
* First, split the specified number of island sectors per continent
* randomly into the island sizes. Sort by size so that larger
* islands are grown before smaller ones, to give the large ones the
* best chance to grow to their planned size.
*
* Then place one island's first sector into each sphere, randomly.
* Add one sector to each island in turn, until they have the intended
* size. Repeat until the specified number of islands has been grown.
*
* If placement fails due to lack of room, start over, just like for
* continents.
*
* Growing works as for continents, except the minimum distance for
* additional islands applies, and growing simply stops when any of
* the islands being grown lacks the room to grow further.
* the islands being grown lacks the room to grow further. The number
* of sectors not grown carries over to the next island size.
*
* 4. Compute elevation
*
@ -1110,6 +1115,32 @@ place_island(int c)
return n;
}
static int
int_cmp(const void *a, const void *b)
{
return *(int *)b - *(int *)a;
}
static int *
size_islands(void)
{
int n = ni / nc;
int *isiz = malloc(n * sizeof(*isiz));
int r0, r1, i;
isiz[0] = n * is;
r1 = roll0(is);
for (i = 1; i < n; i++) {
r0 = r1;
r1 = roll0(is);
isiz[i] = is + r1 - r0;
isiz[0] -= isiz[i];
}
qsort(isiz, n, sizeof(*isiz), int_cmp);
return isiz;
}
/*
* Grow the additional islands.
* Return 1 on success, 0 on error.
@ -1117,25 +1148,27 @@ place_island(int c)
static int
grow_islands(void)
{
int n = ni / nc;
int stunted_islands = 0;
int *island_size = size_islands();
int xzone_valid = 0;
int carry = 0;
int i, j, c, done, secs, isiz, x, y;
init_spheres_of_influence();
for (i = 0; i < n; i++) {
for (i = 0; i < ni / nc; i++) {
c = nc + i * nc;
if (!xzone_valid)
xzone_init(c);
isiz = roll(is) + roll0(is);
carry += island_size[i];
isiz = MIN(2 * is, carry);
for (j = 0; j < nc; j++) {
isecs[c + j] = 0;
if (!place_island(c + j)) {
qprint("\nNo room for island #%d\n", c - nc + j + 1);
free(island_size);
return 0;
}
}
@ -1163,18 +1196,18 @@ grow_islands(void)
xzone_valid = 0;
}
for (j = 0; j < nc; j++)
stunted_islands += isecs[c + j] != isiz;
for (j = 0; j < nc; j++)
qprint(" %d(%d)", c - nc + j + 1, isecs[c + j]);
carry -= secs;
}
free(island_size);
qprint("\n");
if (stunted_islands)
qprint("%d stunted island%s\n",
stunted_islands, splur(stunted_islands));
if (carry)
qprint("Only managed to grow %d out of %d island sectors.\n",
is * ni - carry * nc, is * ni);
for (c = nc; c < nc + ni; c++)
find_coast(c);