Showing posts with label Case Study. Show all posts
Showing posts with label Case Study. Show all posts

October 19, 2022

Detail XV: Farms in the Hinterland

What lies between the settled areas and the "true" wilderness? And how can we determine this from the wilderness maps?

Let's begin with an example region featuring two settlements. The settlement to the left is about 6000 persons, and the right much smaller, about 130. These numbers refer only to the urban population of the settlement proper. This population number is the source of infrastructure numbers, and for that reason is fixed.

lighter "wilderness" hexes can be considered cultivated

Of course, not everyone lives in the settlement, and so we consider that 85% of the 20hex's total population is rural. This comes out to about 15000, and then increases to 18000 due to market spread. Already we have a problem: how are all these people fed?

As a note: the intent is not to micromanage the result such that every individual of hundreds of thousands of people each have their determined job, place, and caloric intake. However, we do want to ensure that our results are consistent and coherent. The players are not interested in the type of detail produced by slavery to the numbers. They want to know (usually) how far outside the town is the dungeon? It is unlikely that a typical dungeon (as understood by most parties) would remain uncleared within several miles of the farming hinterland. We must make the numbers serve us instead.

For some reason, the online worldbuilding community is convinced that a square mile of farmland can support 180 people. I'm not sure what the origin of this number is, and I can't exactly say that it's wrong, but it certainly ignores the incredible variability of arable land and agricultural technology. But let's pretend it's a viable average at least, so we can see where we land.

Our total population of ~24000 people, then, will require some 153 1hexes of farmland outside the city (each 1hex is 0.866 sq mi). The 20hex itself is only 400 1hexes. That certainly reduces the tight feel of the map above into something essentially cleared of all trees and wilderness.

Alternatively, we can take the 6000 as the total population. That requires about 41 1hexes to feed. There are 26 1hexes on the above map which are adjacent to settled hexes. So let us assume that the heavy cultivation of those hexes (including farming, orchards, timber management, and hunting) added to any small-plot cultivation of the denser settled hexes yields the caloric requirements of the 20hex.

Quite a lot of work to end up back at the same square. However, there are some key takeaways from this experiment nonetheless.

  1. The adjacent wilderness hexes are not pure wilderness, and in fact are probably heavily farmed. No orc lairs here.
  2. For this map in particular, the smaller settlement, although tiny in comparison to the larger, controls a slight majority of the productive land (which it likely sends a few miles down the road to the larger settlement). This is probably a collection of holdings of 1-3 knights who are tied in some way to the larger settlement.
  3. As a corollary, the smaller settlement will have about the same number of agricultural class with a much smaller merchant/elite class. They will depend heavily on the larger settlement for military protection and most market services.
  4. There are about 75% fewer people in these hexes than I'd previously thought. That will have significant implications if questions arise about hex wealth or the mustering of an army.

August 10, 2022

Weather Engine

Way back when I first started coding up this project (several years ago now), one of the first things I implemented was Alexis' weather generator.

It works pretty well. Working with real-world data as the seed input is easy. I've extended the system a little bit to make it more versatile throughout the year.

The only bits of data I need are: minimum and maximum monthly temperature in Fahrenheit (high and low), and the months in which the high occurs. I also collect high and lows for the precipitation (in mm) and the month in which that high occurs.

"climate": {
	"temperature": {
		"minimum": {
			"high": 77,
			"low": 47,
			"highMonth": 7
		},
		"maximum": {
			"high": 89,
			"low": 62,
			"highMonth": 7
		}
	},
	"precipitation": {
		"high": 126,
		"low": 70,
		"highMonth": 7
	}
}

With these numbers, it's a simple enough matter to fit a sinusoidal curve to give me the monthly average high and low for any given month. Admittedly, very few places on earth have a perfectly balanced summer/winter cycle, but this can be forgiven, and the players are unlikely to notice in any case (particularly across such a relatively small area).

A whole year of temperatures

I've incorporated a few extra bits into my version of the weather engine. The first is apparent temperature. At higher temperatures (80F+), high humidity makes the air seem hotter. This is usually reported as Heat Index. Conversely, when the air is cold, wind can make it feel even colder (Wind Chill).

Next, I used a IDW algorithm (my go-to) to spoof data for all hexes based on just a few inputs. I grabbed a few stations from around the State, but with this method, I don't need to worry about researching all 170+ points.

On one of the original weather posts, Vlad made a comment about how much rain it generates. These are some good thoughts for possible mods. I don't see that problem cropping up at the moment, but it's something I'll keep an eye on.

As another potential update, I could use a Gaussian distribution to generate the temperature for each day, or calculate the daily drift differently. But for now this works well.

April 9, 2021

Detail XIII: A Case Study VII

One full region is now generated:

There's plenty of material here, of course, but I can do better, particularly with the addition of features. Let's zoom in on the capital city here (Hex 25, infrastructure 42).

The first and easiest thing to place is a bridge. Hex 25 has a high enough infrastructure to be able to place bridges (as opposed to ferries or fords). This river has a Strahler number of 4. Therefore, the two hexes where the roads cross the river will have bridges on them, notated by black squares (for now).

I recommend reading through this series of posts to understand where I'm going next. We want to know what features this hex has by virtue of the specific layout. Moreover, it'd be nice if this were a true function: that is, for a single input of hexes, we have a single output set of features. That will allow us to save some storage space, since all we'll need to know is the original layout.

To place these features, we loop through the hexes from highest to lowest infrastructure - not worrying about whether the hex is itself civilized. That is, for a hex and its six neighbors, if there are 4/7 civilized hexes present in that set, then the central hex is of Type 4, quite good. Depending on the exact distribution of those civilized hexes (Type 4 has 8 possible layouts), the possible features could be a large keep with a village, a manor house with a village, an aquifer, or a quarry. Once a feature has been identified, all hexes in the set are removed from the list: this prevents the map from getting too busy.

I've only added a few things to the list given by the Tao above. But there are a lot of configurations which are empty - again, that's fine. Scarcity breeds innovation.

In addition to the bridges, we generate a medium keep with village and church, a toll road, several mines, and a quarry. Additionally, there are several outlying hexes with no specific feature, but which in this case would most likely be farms or other "non-village/city" communities of a few families.

I could also make use of the wilderness and deep country features discussed here; but that would need be on a different layer, not player-facing. Still, could be a useful DM tool.

March 26, 2021

Detail XII: A Case Study VI

Next up: lakes.

Lakes were complex to handle back in Detail VI: Lakes, but this project should be much simpler; again, I am placing them manually. Hex 15:

There are two important things to note here. One, I trace a river through the center of the lake to ensure that drainage is calculated properly. Second, the road hugs the river pretty nicely this time.

What I've got so far:

March 19, 2021

Detail XI: A Case Study V

Let us take stock of the map so far, with Hexes 24, 25, and 26.

The terrain blends very nicely. But these settlements need to be connected - at least, if the infrastructure exists to support them. The infrastructures are as follows: Hex 24 with 9, Hex 25 with 16, and Hex 26 with 7. Not a great deal of population here to maintain a good trail, but it's enough to at least have a road of some kind.

Road placement uses an A* algorithm with defined endpoints. In the cases here, the endpoints are the defined settlement hex and the edge exits; if no settlement exists I'll just define two exits.

The route weight is a bit complex but generally tries to pick the route with the most gradual elevation change. These being rather flat hexes, we'd expect a more or less straight road. There's some complexity when it comes to rivers. Unless a 20-hex has at least 12 points of infrastructure, it can't build a bridge or ferry. If it has less than this, it can't have a simple ford either if the river is larger than 2 Strahler points. Those rules yield the following network:

Pretty good. Nothing complex to overcome in this particular slice. We can get slightly more interesting results by adding a bit of a terrain penalty. Hex 26 is mostly marshy terrain - not necessarily impassible, but the road will definitely hug firmer terrain where available. So we'll add in a bit of a penalty for such.

Eh. Kind of interesting. The penalty weights probably need tweaking but I'll wait until I have more use cases.

March 17, 2021

Detail X: A Case Study IV

Under normal circumstances, I would place the rivers at this point. However, I am adding them by hand. Rivers are saved as a list of the hexes through which they flow, which makes this part more or less trivial. The Strahler numbers are saved for each in-flow hex and so the width of the river can be drawn accurately.

Hex 25; river in white temporarily for emphasis

The next step is determining which hexes are settled and which are wild. The infrastructure for Hex 25 is $I=16$. This isn't quite as simple as placing, for instance, 16 of 400 hexes as "settled." I reviewed the system for determining the relationship between infrastructure and number of settled hexes back in Detail III: Infrastructure. Briefly, each hex contributes to the total infrastructure based on the number of settled hexes that it itself borders.

There are then two broad scenarios for placing these hexes. The first is the case here, where I already know the "core" location of the main settlement within the hex. I want the other settled hexes to "cluster" around this one, so the base chance of settlement ($P_s = I/400$) is modified based on proximity to the constraints (there may be more than one in other cases): \[P_s = \left(\frac{I}{400}\right)^{|s - c|\cdot t}\], where $|s-c|$ is the distance between the 1-mile hex $s$ and the constraint $c$, and $t$ is a factor such that the sum of probabilities is equal to $I$. This added factor makes convergence a lot faster. Thanks to Scott for this idea!

For now I'm coding the settled hexes as grassland. The algorithm yields two Type VII hexes (1) and four Type VI hexes (2) for a total of $2\times1 + 4\times2 = 16 = I$. Perfect! In this case, they are all contiguous, but this need not be the case. Just luck of the draw and a consequence of the low overall infrastructure. 16 is really not very much at all.

The second scenario (and honestly, more common) is a 20-hex without a named settlement, and thus no specific constraint. Settled hexes will then tend to cluster around river features or roads. Therefore, we can do a similar adjustment with the distance to a random river or road:


However, most of the 20-hexes I'm looking at initially will have settlement features. This will come in handy later on.

March 15, 2021

Detail IX: A Case Study III

I previously covered terrain placement in Detail III and a bit in Detail IV. At the time, I was thinking of the effect that infrastructure had on the terrain, and so I used the terms somewhat interchangeably. The terrain type was simplified into "primary" and "secondary," but there are many cases where neighboring 20-hexes may have several different types between them. So the system needs to be able to take that into consideration.

At first, I just used a random choice between the available neighbor types, yielding something a bit like this:

This isn't really great, because the shape of the 20-hex is immediately identifiable.

To the surprise of no one, I'll turn to my old friend IDW. Normally, IDW is concerned with interpolating numerical values. Instead, for each hex, I'll determine the weights assigned for each potential terrain type. The 20-hex terrains are as follows:

Darker green is shortleaf pine (coded as c), lighter green is longleaf pine (n). Not a huge difference but adds some flavor. The green-brown is marshy terrain and not in view here. So we see that Hex 24 will be dominated by shortleaf pine and begin to transition to longleaf towards the south. Running the algorithm for the weights on a 1-hex near the bottom yields:

{'c': 1.3e-06, 'n': 1.9e-06}

So the longleaf pine is much more likely to be generated near the bottom. To use this in a random selector, I normalize these numbers to sum to unity.

{'c': 0.401, 'n': 0.599}

So there is about a 60% chance that that 1-hex will be longleaf as opposed to the dominate shortleaf.

Quite satisfying.

Detail VIII: A Case Study II

I had previously worked on height generation here: Detail I: One Mile Hexes. The underlying terrain is one of the more fundamental issues to tackle, as it determines road and river placement.

However, as we shall see, it's not of first priority for this particular Case Study. In the general case, the topography is important for placing rivers and other features; it'll be important here for roads, but rivers are all predetermined.

With that in mind, the altitudes of each 20-hex are defined as best I can. The 20-hex I'll work on first is designated No. 24. Its neighbors are 14, 15, 23, 25, 34, and 35. The heights for each of these must also be defined, or at least for most of them if available.

With these in hand, we can use IDW to get weights for each 1-hex based on the distance to the centers of the neighboring 20-hexes. The IDW output is heavily dependent on the number of neighbors $k$ and the exponent $x$ used to control the drop. The following graph shows the altitudes of a line of hexes across the middle of 24 and 25, with $k=2,\, x=2$.

Applied to all subhexes, the altitude is as follows (heights exaggerated for display, these low heights do not show up well in greyscale):

Some artifacts are still just barely visible, because $k=2$ means that only the central 20-hex and the closest neighbor will matter. Expanding that to $k=3, x=3$ may yield better results. There are still some artifacts, but these will probably get washed out when we add a little noise.

The amount of noise is determined by the topography type. Hex 24 is coded as "hills," and so the standard deviation of the gaussian function is set to $\sigma=150/6$. I'm still playing with those values: that is not a lot of height variation over 364 sq miles. Hex 25 has a topography of "plains," so the gaussian is contracted to $\sigma=25/6$.

 

That's not looking too bad. I considered a further "relaxation" step, where each hex would spill a bit of its height into its lowest neighbor. But that would require information we don't have in the self-contained system for the border hexes, and might lead to edge artifacts when 20-hexes are combined. So for now this seems good enough.

March 11, 2021

Detail VII: A Case Study I

The more work I have to get done in real life, the more my thoughts turn to working on The System. Particularly, I hadn't worked on the 1-mile generator in a while, and it was brought back to the front of my memory while proselytizing for the Higher Path recently. To try and refine a lot of that spaghetti, I decided to remake the area around my home into a (more) low-tech fantasy region.

Of course, Tao (Alexis) of the Higher Path bases his world on the late medieval/early Renaissance Old World. This side project will be similar, with the terrain and some of the demography based loosely in the "real world."

A major advantage of this project is that it makes the final product much more personal. At some level, a project based solely on imagined and random numbers has little soul - particularly in the development stage, where whole universes are destroyed and remade with a click. However, designing an alt-version of an area I'm intimately familiar with not only has soul, it has stakes. I've got real physical and spiritual blood in this land, and that naturally translates into greater care and eye for detail. If something is made up from whole cloth, there can be no accountability. These are places that I know personally - the decision to erase or augment them is felt more deeply.

To avoid totally doxxing myself (is anyone really anonymous online?), placenames will be concealed for now - and perhaps remade anyway to be more "fantasy."

I started with a 20-mile hex (20-hex hereafter) map of the whole State. Working from waterway and ecological maps, I assigned rivers and major vegetation types.

Normally, I would calculate hex-by-hex drainage for the river width. However, in the larger system I use, one 20-hex only drains to one other. In the real world, its commonplace for more than one river to flow through a single area of this size. It's over 364 square miles, of course. Instead, I used the Strahler number. The other advantage of using real waterways is that I can avoid the many issues I had with automatically placing rivers on the 1-hex maps. I had something that worked but it was kludgy, and hopefully I can return to it with more knowledge and a fresh brain in the future. Rivers can be manually input either way, and saved for future processing.

I'm a bit less strict on roads - since the modern era has roads criss-crossing every which way, I decided to preserve a handful of existing connections but largely rewrite the road network, and allow my algorithms to handle the internal road placement.

To determine settlement placement, I used only cities that were incorporated in the State by 1900. This cut the list down to 47. I use Alexis' infrastructure system to distribute infrastructure points, by dividing the 2010 population of each city by 10. This part made me very grateful for my code on the bigger map - doing this by hand was a chore. If I make any changes to the populations, I'm going to have to either do it all over again, or figure out how to apply the infrastructure algorithm I've already written to this subset of hexes.

But for now it is what it is. Road type and the presence of bridges or ferries (as opposed to simple fords) is determined by the infrastructure number, so its important to know.

My general plan for tackling and describing this project is as follows.

  • Quickly review the height algorithm. The area is best described as "flat and low," so we'll see if that generates any problems.
  • Refine the terrain assignment such that there is a "smooth" interpolation between 20-hexes of different terrain types. Like the height algorithm, discussed in previous posts, the ultimate goal here to create a distribution where the hex edge cannot readily be identified.
  • Because I'm working from a scale of 20 miles all the way down to 1 mile in a single step, I think I lose of some of the beauty of Alexis' working down to 6 miles and then to 2 miles. So I'll revisit the infrastructure assignment as well to try and beautify it. I'm not sure if the low infrastructure will help or hurt here but we'll see.
  • Once the settled/wilderness hexes are placed, roads and trails/tracks can be placed. There's always tweaking to be done when A* pathfinding is involved.
  • From there I'd like to consider types of features (of civilization) which could be placed based on waterways, settlement, and roads.
  • Lakes or coastlines. I may get to this one earlier; it's not as crucial since I'm manually placing these features.
As each piece of the puzzle is added, the gameability grows richer.