I alluded to this mechanism in the previous post. I want to see how tribal hunter-gatherer societies, with small carrying capacities (around Dunbar's number) spread and grow through time without the added constraints of the full historical generator.
Each tribal polity can only occupy one hex at a time (not a strictly realistic assumption, but we can simply say that there are no other polities of note in the area). Carrying capacity $K$ decreases as resources in the hex are used up. Once $K$ converges with the population size, the tribe must either move or split to maintain balance. When a tribe leaves, the area begins to recover.
There are certain hexes with a high desirability which serve as generators: once a tribe reaches one, there's never any incentive to leave, and so more and more tribes are spun off as a result. When I add discoveries, these will become probable Ur-city locations.
The desirability issue is particularly obvious when a saturation point is reached. I've not yet added oceanic migration, so the tribes bounce around from place to place like so many gas molecules in a closed container.
(I feel compelled to point out that 1500 years is a pretty long time. In 519 AD, the Kingdom of Wessex was founded. In fantasy, we typically deal with deep-time related to people groups - thousand year reigns are not unusual. In real life, empires are generally much more temporary.)
This simulation progresses much faster than the "civilized" simulation, due to code rewrites and the fact that these tribes aren't doing much other than running around and eating all the wildlife.
In these first runs, I noticed that the raw desirability, which is the main selection factor, is far too high for areas that humans (the only race I'm working with for exploratory purposes) would normally avoid, such as deep tundra. So that will need to be fixed. I also want to add a mechanism for tribal warfare, if there is a some greener grass on the other side but it's occupied already.
Showing posts with label Desirability. Show all posts
Showing posts with label Desirability. Show all posts
December 28, 2019
June 7, 2019
History XIV: Here I Stand (Summary)
I thought for a bit on how to present a total overview of the system (suggested by Ted), but there are so many moving parts. Still, it's good to sit down and think about it a bit.
This ought to help in keeping things straight. Or perhaps it makes it even more confusing.
It's clear there are several feedback loops: most notably that the city growth rate is affected by the overall tech level of the hegemony. This provides a significant obstacle to small starting cities, but gives a boost to established empires. The loops keep things interesting. In addition, many of these links involve some randomness, which means that things will generally tend in the same direction each time I run the whole simulation, but it's never going to be exactly the same.
Desirability is a value, expressed as a percentage, which describes how desirable a piece of land is for settlement. Each race prefers a different arrangement of terrain and weather. The desirability value will affect how large a settlement can arise in a hex, and also captures the number of resources available there (whether or not they are being totally utilized). Because the resource allotment code adds complexity and time to the history simulation, the desirability is used as an approximation of resources in the battle simulator (since a settlement with access to more physical resources will have an inevitable edge over their adversary). Raw desirability is the desirability in the absence of civilization; it is mixed with infrastructure to obtain a measure of desirability for city expansion, when an existing settlement sends out settlers.
Infrastructure is an integer which describes the effect of settlements on surrounding terrain. Although the Tao only uses elevation to limit the spread of infrastructure, I also include local effects such as forest or desert. I also make infrastructure "flow" downriver easier than upstream. A high enough infrastructure (over 400, for now) changes a forested hex into plains or grassland, depending on the local climate (which is a feedback element encouraging a more efficient infrastructure spread). A higher infrastructure implies a better training mechanism for soldiers. Infrastructure spreads from every settlement in a hegemony and stops at the border.
Hexes with infrastructure but no settlement are the hinterlands; they are prime candidates for future settlements. Since the hinterlands are populated (however sparse), reinforcements can be press-ganged. Generally, however, their population is very low. The rural population of any hex with an infrastructure value is an exponential function of that infrastructure number.
If the effect of a hegemony's capital (measured in % of total infrastructure in a hex) drops too low, and a city's self-generated infrastructure is high enough (100), then a rebellion is possible.
Available resources (which are fed into the market system, not shown) are acquired by cross-referencing the available resources (which is somewhat determined by terrain) with the resource definitions. Certain resources cannot be extracted by low-tech cultures, but may become available as the hegemony grows.
The Long-awaited GitLab. There is no README yet: I've been working on this for two years now, and so the code is a garbled mess in places and cleaner in others. Eventually I'll get around to some housekeeping. Enter at your own risk.
It's clear there are several feedback loops: most notably that the city growth rate is affected by the overall tech level of the hegemony. This provides a significant obstacle to small starting cities, but gives a boost to established empires. The loops keep things interesting. In addition, many of these links involve some randomness, which means that things will generally tend in the same direction each time I run the whole simulation, but it's never going to be exactly the same.
Desirability is a value, expressed as a percentage, which describes how desirable a piece of land is for settlement. Each race prefers a different arrangement of terrain and weather. The desirability value will affect how large a settlement can arise in a hex, and also captures the number of resources available there (whether or not they are being totally utilized). Because the resource allotment code adds complexity and time to the history simulation, the desirability is used as an approximation of resources in the battle simulator (since a settlement with access to more physical resources will have an inevitable edge over their adversary). Raw desirability is the desirability in the absence of civilization; it is mixed with infrastructure to obtain a measure of desirability for city expansion, when an existing settlement sends out settlers.
Infrastructure is an integer which describes the effect of settlements on surrounding terrain. Although the Tao only uses elevation to limit the spread of infrastructure, I also include local effects such as forest or desert. I also make infrastructure "flow" downriver easier than upstream. A high enough infrastructure (over 400, for now) changes a forested hex into plains or grassland, depending on the local climate (which is a feedback element encouraging a more efficient infrastructure spread). A higher infrastructure implies a better training mechanism for soldiers. Infrastructure spreads from every settlement in a hegemony and stops at the border.
Hexes with infrastructure but no settlement are the hinterlands; they are prime candidates for future settlements. Since the hinterlands are populated (however sparse), reinforcements can be press-ganged. Generally, however, their population is very low. The rural population of any hex with an infrastructure value is an exponential function of that infrastructure number.
If the effect of a hegemony's capital (measured in % of total infrastructure in a hex) drops too low, and a city's self-generated infrastructure is high enough (100), then a rebellion is possible.
Available resources (which are fed into the market system, not shown) are acquired by cross-referencing the available resources (which is somewhat determined by terrain) with the resource definitions. Certain resources cannot be extracted by low-tech cultures, but may become available as the hegemony grows.
The Long-awaited GitLab. There is no README yet: I've been working on this for two years now, and so the code is a garbled mess in places and cleaner in others. Eventually I'll get around to some housekeeping. Enter at your own risk.
January 30, 2019
Roads III: Across the Wilds
The building of roads must be more dynamic.
Yes, a certain infrastructure must be in place for a road to start. But it is misguided (as I have tried previously) to require that same level of infrastructure for each intermediate hex. Roads will frequently be built across areas of wilderness. How do I capture this?
The road, after all, merely connects two locations. It is not itself a location. So while we might require an infrastructure index of, say, 50 to begin and end a road, it might pass through many areas where the infrastructure index was much lower, like 5 or 10.
A bridge (generalized river crossing) also should not be a static threshold, but should vary based on the size of the river (measured by drainage $d$). \[I_d = 100 \ln(d)\] Bigger rivers require a large infrastructure to be built to maintain their bridges.
Maintained roads are not the only option for travel. Cart trails or other paths can be available as well. So perhaps the "road system" should be primarily for heavy trade, and not necessarily for point to point movement of a player party.
I could also check if two locations can already be connected before placing a new road between them. This would reduce the total number of roads which need to be placed. However, just having a single connection is not enough. We can easily imagine a scenario in which a road between two distant cities is placed among the most optimal route at the time, but 100 years later, a more favorable route (perhaps through a large intermediate city) is possible. We can't expect our people to shrug because there's already a road there! So perhaps this can be tweaked.
That still doesn't improve things a lot. But - maybe they don't need to be "improved." A country with a road system like this could be a military or industrial power.
Limiting the number of roads by population of a city?
Yes, a certain infrastructure must be in place for a road to start. But it is misguided (as I have tried previously) to require that same level of infrastructure for each intermediate hex. Roads will frequently be built across areas of wilderness. How do I capture this?
The road, after all, merely connects two locations. It is not itself a location. So while we might require an infrastructure index of, say, 50 to begin and end a road, it might pass through many areas where the infrastructure index was much lower, like 5 or 10.
A bridge (generalized river crossing) also should not be a static threshold, but should vary based on the size of the river (measured by drainage $d$). \[I_d = 100 \ln(d)\] Bigger rivers require a large infrastructure to be built to maintain their bridges.
Maintained roads are not the only option for travel. Cart trails or other paths can be available as well. So perhaps the "road system" should be primarily for heavy trade, and not necessarily for point to point movement of a player party.
I could also check if two locations can already be connected before placing a new road between them. This would reduce the total number of roads which need to be placed. However, just having a single connection is not enough. We can easily imagine a scenario in which a road between two distant cities is placed among the most optimal route at the time, but 100 years later, a more favorable route (perhaps through a large intermediate city) is possible. We can't expect our people to shrug because there's already a road there! So perhaps this can be tweaked.
That still doesn't improve things a lot. But - maybe they don't need to be "improved." A country with a road system like this could be a military or industrial power.
Limiting the number of roads by population of a city?
This might work. But I still need to tweak it to generate longer networks.
January 17, 2019
Infrastructure II: History I
Time to begin placing cities.
There are a few considerations to make when growing populations/cities organically.
There are a few considerations to make when growing populations/cities organically.
- Initial populations of villages are set to $P_0 = 150$. The growth equation at time $t$ then becomes \[P(t) = {K \over {1 + {K - P_0 \over P_0} e^{-r t}}}\] In the future, I'll actually progressively modify the population number, but for now I just evaluate this equation using the age of the city.
- The carrying capacity $K$ is a function of the desirability $D$ of the location. \[K_0 = 5000 \exp\left(10 \left({D \over \textrm{max}(D)} - {1 \over 2}\right)\right)\]
- $K$ is then modified according to Central Place Theory (CPT). One of the tenets of CPT is that cities are spaced according to the product of their populations and inversely to the distance between them. My method for doing this is as follows: the city in question is assigned a level $\ell = \log_{10} K_0 - 1$. $K_0$ is then reduced by a factor of 10 if $2 ^ i > \delta_c$ for all $i < \ell$, where $\delta_c$ is the distance to the closest city of the same $\ell$. So a city of 9500 people cannot be closer than 4 hexes to another similarly sized city. If it is, then $K_0$ is reduced by a factor of 10. This will hopefully ensure an exponential distribution of city sizes, and prevent a concentration of very large settlements.
- $r$ will be a random number with a max of $2\% \cdot D \over \textrm{max}(D)$. This sets the maximum growth rate at 2%, but allows for a lot of variation in between. Maybe the different races should have different growth rates?
- Any given hex which meets all other requirements has only a 5% chance of generating a city. I'll give this a little boost for particularly desirable places.
- I won't force them to obey Zipf's Law, but I'm wondering how the distribution will shake out. Zipf's Law has been demonstrated to hold most true for "small cities" over 100,000 - for a fantasy low-tech world, that might be a "huge city" instead!
- Another thing I need is a mechanism to destroy or stagnate a town - many things can affect a city's growth or longevity. Not every city built in 1000 BC still exists. In fact, most don't. Plague, famine, war, resource depletion, etc can all wipe out even large settlements.
- A dynamic $K$ value might be cool also. That way a settlement might have a bright future, but overcrowding could really hurt long-term. As groups compete for resources, which larger cities need more of, smaller settlements tend to be crowded out. I need to capture that, and that might help my goal of CPT-arranged cities.
Some observations:
- Since dwarfs (blue cities) are not "constrained" to the coast, their cities are placed much faster. This isn't necessarily a problem, but I want to consider how heavily the coast is weighted vs the inland. As a result, non-dwarfen cities are isolated, and have more difficulty coalescing into an entity.
- The desirability map takes a dozen seconds or so to populate. This adds up and makes the year-by-year simulation very slow.
- Similarly, it's expensive to figure out where roads should be placed so that they make sense. I've added some timeout functions to the road placement algorithm to make sure that A* doesn't get stuck somewhere it can't get out, but the constraints need some work. As shown in these images, it's made slower by the fact that eventually, every city gets a full 6 roads coming in and out.
- Some of the orc cities (purple) behave well with roads, but there are no special road considerations for different races.
- River crossings are a problem. They would be easier to implement if I used edges instead of tiles, but that would be a big pain to implement with the drainage code.
After 550 years of simulation, the total city populations are as follows (not including rural population, which is expected to be about 5x urban):
| elf | 13,552,065 |
| dwarf | 5,570,650 |
| halfling | 11,144,894 |
| orc | 28,884,984 |
| human | 14,688,643 |
Orc growth is much faster because their cities form at great distances from the other, allowing for rapid growth and large carrying capacities from CPT. The opposite is true of the dwarfs: they have many cities, but densely packed, which reduces the maximum carrying capacity.
I could do more analysis of the cities, but I'd like to tackle the road problem first, since it feeds back into the city placement algorithm, and is the current bottleneck for any kind of long-term simulation.
January 11, 2019
Desirability IV
As discussed in previous posts, the presence of cities and infrastructure can make a location more desirable. Shown here for elves:
![]() |
| without city modifier |
![]() |
| with city modifier |
Currently, the cities are undifferentiated with respect to race - my end state will be to have more eclectic populations - but for placing initial cities, I may want to change that temporarily.
The next steps are to put it all together in a coherent whole model.
January 10, 2019
Roads II
With the rough infrastructure map in hand, I wanted to be able to place roads between them. Then both systems could be fed back into the desirability model.
But as usual, there were some kinks to work out. There are a few constraints on the roads, such as climbing distance (too steep? penalty), altitude (particularly above 8000 ft, where the air is thin for those not acclimated), and of course overall length. Additionally, a hex must have a certain infrastructure threshold to even be considered for a road, and it's even higher for a bridge to cross a river.
But as usual, there were some kinks to work out. There are a few constraints on the roads, such as climbing distance (too steep? penalty), altitude (particularly above 8000 ft, where the air is thin for those not acclimated), and of course overall length. Additionally, a hex must have a certain infrastructure threshold to even be considered for a road, and it's even higher for a bridge to cross a river.
I don't mind the jaggedness of the line - the hexes are huge, after all. It's the overlapping roads I want to avoid. So I fixed it to seek only the closest city for a road. This is similar to a minimum spanning tree, but not exactly. I want a non-optimal layout - the spread of populations shouldn't always make sense.
These maps also show how the infrastructure (red) is affected by local topography, which constrains it from spreading too far.
Now, I can feed both of these systems into desirability and start building more organic layouts (the cities I used here are just randomly selected).
January 4, 2019
Infrastructure I
In my discussion on desirability (for population centers), I realized that existing infrastructure is extremely important. Communities can exist in isolation but will inevitably spread themselves out, creating new communities and so on.
Eventually, I'll split infrastructure out into separate races (at least for the desirability index). Infrastructure, of course, determines what sorts of services and industries could be available in a given hex, so I only need a single (non-racial) number eventually. But as far as settlement placement goes, it would make more sense that an elven village would prefer other elves rather than humans or dwarfs, given the chance. I can also define rough guidelines to racial relations - humans and elves might get along better than humans and dwarfs, and who likes the poor, stereotypically brutal orc?
However, making this switch is pretty easy, so for now I'll work with a single value. This will make settlements more heterogeneous during these tests.
To really get an accurate base number for infrastructure, I need a value for the total population in a region (or the whole world, as it may be). This part is tricky when starting from scratch and looking at the entire planet - I don't know how many people there are, and where they live. After all, that's the point of this system in the first place.
The equation in question is as follows, where $I_{i,0}$ is the base infrastructure index of the $i$th city, $p_i$ is the population of the $i$th city, $p_t$ is the total population (urban and rural), and 346 is the number of square miles in a 20-hex:
\[I_{i,0} = {p_i \over 346} {\sum_i p_i \over p_t}\]
Essentially, I am ignoring the ${\sum_i p_i \over p_t}$ term, because I don't (yet) have access to $p_t$. Or I could make up a number. Ignoring it is the more palatable option, but adding a multiplicative factor will make the influence of a settlement "reach" farther.
Placing a bunch of random cities and applying those rules:
Eventually, I'll split infrastructure out into separate races (at least for the desirability index). Infrastructure, of course, determines what sorts of services and industries could be available in a given hex, so I only need a single (non-racial) number eventually. But as far as settlement placement goes, it would make more sense that an elven village would prefer other elves rather than humans or dwarfs, given the chance. I can also define rough guidelines to racial relations - humans and elves might get along better than humans and dwarfs, and who likes the poor, stereotypically brutal orc?
However, making this switch is pretty easy, so for now I'll work with a single value. This will make settlements more heterogeneous during these tests.
To really get an accurate base number for infrastructure, I need a value for the total population in a region (or the whole world, as it may be). This part is tricky when starting from scratch and looking at the entire planet - I don't know how many people there are, and where they live. After all, that's the point of this system in the first place.
The equation in question is as follows, where $I_{i,0}$ is the base infrastructure index of the $i$th city, $p_i$ is the population of the $i$th city, $p_t$ is the total population (urban and rural), and 346 is the number of square miles in a 20-hex:
\[I_{i,0} = {p_i \over 346} {\sum_i p_i \over p_t}\]
Essentially, I am ignoring the ${\sum_i p_i \over p_t}$ term, because I don't (yet) have access to $p_t$. Or I could make up a number. Ignoring it is the more palatable option, but adding a multiplicative factor will make the influence of a settlement "reach" farther.
Placing a bunch of random cities and applying those rules:
I'm excited to lay down some roads on this bad boy (and to feed it back into the desirability map).
January 1, 2019
Desirability III
I am working on making the desirability index more parameterized. With this, I can create sets of parameters for each race, because humans, elves, etc will not desire the same climates, terrain, or biomes for their habitations.
I'll probably be tweaking those recipes for a long time. I haven't looked into details on the races (5e is, of course, deeply unsatisfying). But I'm not worried about that for now.
Most races avoid the rainforest - the soil is often poor for many types of crops. Dwarves like mountains and avoid the coast - but they're not total loners so they'll utilize rivers for travel. Stuff like that.
This is a hard map to read - essentially I've layered five races on top of one another; humans: green, elves: red, dwarfs: blue, halflings: orange, and orcs: purple. Why those five? No idea. I wanted the three classics, plus a feature race for ice and desert climates that would be inhospitable for the others. The orcs end up with a lot of territory, but they are not as gregarious (modeled with an infrastructure penalty), so the size of their empires should theoretically be limited. The elves also have a wide distribution thanks to the large amount of rainforest (unless I penalize them for it also).
All of this is, of course, very modular. It's easy to change the climate models and then propagate those changes to the desirability. This is a far cry from where I was earlier this year, where a map like this would require tons of manual rework.
Creating this Step 0 desirability map is more or less straightforward (tweaking is, as always, necessary). However, existing infrastructure will also affect the terrain...but I haven't built any of that code, so that will need to be next.
I'll probably be tweaking those recipes for a long time. I haven't looked into details on the races (5e is, of course, deeply unsatisfying). But I'm not worried about that for now.
Most races avoid the rainforest - the soil is often poor for many types of crops. Dwarves like mountains and avoid the coast - but they're not total loners so they'll utilize rivers for travel. Stuff like that.
This is a hard map to read - essentially I've layered five races on top of one another; humans: green, elves: red, dwarfs: blue, halflings: orange, and orcs: purple. Why those five? No idea. I wanted the three classics, plus a feature race for ice and desert climates that would be inhospitable for the others. The orcs end up with a lot of territory, but they are not as gregarious (modeled with an infrastructure penalty), so the size of their empires should theoretically be limited. The elves also have a wide distribution thanks to the large amount of rainforest (unless I penalize them for it also).
All of this is, of course, very modular. It's easy to change the climate models and then propagate those changes to the desirability. This is a far cry from where I was earlier this year, where a map like this would require tons of manual rework.
Creating this Step 0 desirability map is more or less straightforward (tweaking is, as always, necessary). However, existing infrastructure will also affect the terrain...but I haven't built any of that code, so that will need to be next.
November 6, 2018
Desirability II: Where Do All the People Go?
I've been getting way behind on posting, largely because of my struggles with getting the climates to fall out just right. I know, I know, there's a fair bit of ad hoc going on here. But I've had some trouble in the past with my climates swinging directly from harsh rainforest to harsh deserts. I've got to figure out some methods to smooth that out.
First of all, I can lower the temperature model. It's not just the rain - although that hurts too. Temperature is an odd bird, especially trying to go from this chart on Cartographer's Guild to some actual numbers that I can use for my model. I may need to step back to those isotherms and see if I can build up the coherent model from that. I've been trying several different math functions to try and get smooth interpolation, but I haven't found one that works.
I want to see more green here. The real world has a lot of green (which is the C climate type, really good for crops and such). Some tweaking improved this. However, there's still very little D (boreal), denoted by turquoise. This isn't really a problem, exactly, but I wonder how much of this is due to the terrain/climate system and how much is due to the errors of the model.
However, I can take another look at my "desirability" maps. I still have some tweaking to do to make the right recipe, and then do it again for all the races I want to include! Here is where the climate distribution shows its ugly belly.
It seems at first glance that there's a lot of empty space. Everyone wants coastline, of course, but no one wants to be in the desert (humans, anyway; I like the idea of desert orcs).
Things to think about:
First of all, I can lower the temperature model. It's not just the rain - although that hurts too. Temperature is an odd bird, especially trying to go from this chart on Cartographer's Guild to some actual numbers that I can use for my model. I may need to step back to those isotherms and see if I can build up the coherent model from that. I've been trying several different math functions to try and get smooth interpolation, but I haven't found one that works.
![]() |
| Koppen map |
However, I can take another look at my "desirability" maps. I still have some tweaking to do to make the right recipe, and then do it again for all the races I want to include! Here is where the climate distribution shows its ugly belly.
![]() |
| The greener, the better |
Things to think about:
- Why did the terrain generator make all my coasts so low? Good coastal access should be a bit rarer - as it is, 98% of coastal hexes are lower than 500 ft.
- How do different climates affect desirability rating? How about resource availability (which system will take years to fully develop, of course)? How about other cities and their cross-country roads?
- How should I start placing cities on here once I like the maps? Of course, I can start work on that model right away, since it's all generated, and refine them in tandem.
June 20, 2018
Desirability I
Where do people live?
My plan is to set rules to determine a value of desirability. Cities will then be placed at the most desirable locations first, and then less desirable. When I get around to the history simulator, this rating will be used to guide the spread of civilizations. Azgaar has a very nice demonstration of this process here.
The base desirability will be 0.
A few thoughts. First, the rivers are looking very nice. There are some which drain uncermonially into the sea after a few dozen miles, and some which arc across the landscape. This map is set to have no endorheic basins but I'll be changing that, maybe even to the 17% Earth value. Second, the ideal bands are still pretty sharp, and I don't really like that. I have my doubts that wind could push enough moisture to form a rainforest across nearly 6000 miles (bottom right). I might need to further reduce the penalty for the tundra.
My plan is to set rules to determine a value of desirability. Cities will then be placed at the most desirable locations first, and then less desirable. When I get around to the history simulator, this rating will be used to guide the spread of civilizations. Azgaar has a very nice demonstration of this process here.
The base desirability will be 0.
| +1 | Coastal hex |
| +1 | Natural harbor (if only one of the hex touches the ocean). I need to think about how I can check for this, since I currently use hex centers and not edges |
| +1 | Per point of river drainage. This might be a little much, since these rivers can get fairly large. The Amazon would, by this system, have a drainage value of about 6800 at its mouth. Predictably then, the city of Belém was the first European settlement on the Amazon |
| +1 | Per number of rivers joining at this point ($n-1$). |
| +1 | Per raw (Stage 0) resource. Some will naturally be worth more than others (gold is better than copper), but overall this will be a good start. |
| +1 | Within a favorable biome. This will capture temperature ranges as well as roughly approximating agricultural potential. It's pretty difficult to find information on specific biome suitability, since mankind is incredibly adaptable. For now, I'll just add this if temperature is between 60 F and 90 F, and if the biome is not E (tundra) or B (desert) |
| -2 | In fact, E or B biomes are likely to be extremely unfavorable to settlement |
| -1 | Mountainous terrain isn't great either |
Applying those simple rules yields this:
![]() |
| Desirability map |
However, I just had a thought that if different races prefer different climates, perhaps I could create a different map for each. Everyone likes river trade, but halflings are particularly suited to the cold and so have penalties in warmer climates, whereas orcs are desert dwellers and build their cities in heat that would make an elf weary. Food for thought. The system is extendable and takes very little time to solve - I've vastly improved the brute force algorithms of a few months ago and now changes are easy to make.
Subscribe to:
Comments (Atom)





















