Table of Contents
- 1. Introduction
- 2. Method
- 3. Other Factors
- 4. The Results
- 5. So what?
I’ve been wanting to do this for a very long time indeed. The City State of the Invincible Overlord (CSIO) came out in the 70’s and a revised edition in 1980 or thereabouts. Over the course of several publications and 18 maps of about 38,000m² each, Judges Guild mapped out and gave basic population statistics for an area (“The Wilderlands”) about the size of modern Libya, or the UK, France, Germany, Italy, Poland, and a bit of Belgium put together.
One thing that was never clear to me was just how wild the “wilderlands” were. There’s not much in the way of roads, and the basic terrain is not open plains but light woods, with some plains interspersed. Did the towns marked trade with each other much? How dominant were the handful of city stats and how dependant on their satellite towns where they in turn? Where would a pirate or bandit lurk and by extension where would patrols be placed to protect the trade routes?
Around 1989 or so I bought a book - Settlements by Meyer and Huggett - in a Cancer Research charity shop which introduced me to Reilly’s theory of retail gravitation (from 1929). The idea was that trade between two settlements could be modelled based on the product of the populations divided by the distance between them raised to some power. Add in some constant multiplier to scale it to specific units and the resulting formula looks a lot like the standard Newtonian one for gravity, hence the name.
The specific reason I bought the book was that I thought that I could use it to somehow model the trade pattern in the Wilderlands of the CSIO. Nearly 30 years have passed since that day and finally I’ve gotten around to it! What can I say? I had a long list of things to do.
The catalyst for finally doing this was two-fold: firstly I had been nursing an idea for a path-finding algorithm for a couple of years which I had hopes for, not only for geographic path finding but for broader applications in code optimisation. Secondly, I stumbled across von Thünen’s model of the “Isolated City State” and how he showed a city state’s surrounding economic area could be seen to diverge from a theoretical model under the influence of terrain and transport factors, something I was seeing in my reading around mediaeval London and its trade patterns. I even found a couple of websites that demonstrated this with some limited path-finding algorithms.
One attractive aspect of von Thünen’s model was that it is essentially pre-industrial and focused on agricultural questions which were broadly applicable back into the mists of time.
So, Reilly used distance, but what is “distance”? Straight line distance is clearly nonsensical; as von Thünen emphasised, the real distance should be measured in time. Since we’re dealing with D&D here, that meant looking at movement rates. But underlying this was a deeper question about the nature of trade. In the von Thünen model, different sorts of produce are segregated into bands around the city state, primarily by their perishability and this maps directly into Reilly’s theory where the power distance is raised to relates to the urgency of delivery. The obvious example is that fresh milk, especially before refrigeration, simply has to be produced near or in the city.
By extension of this idea, it’s clear that on the scale of the Wilderlands maps very little trade is done in such products and if the CSIO needs milk it must be producing it itself in the surrounding hex of farmland or getting from very close-by up the Twilight Road or down the Old South Road. In any case, such things would not make up a huge amount of the trade on the map as published, where roads are very rare indeed.
For the sort of bulk non-perishable goods I was thinking about - timber, grain, metals, wine etc. - the value drops of linearly. Which is to say that the value of the product is constant, at least on a time scale of a season or two, and profit is eroded as much by the costs of the fifth day on the road as it is on the first. For milk, the second day erodes profit much faster than the first, and by the fifth you’ve got nothing left to sell.
This makes Reilly’s power simply equal to one. Since I’m only looking at relative levels of trade I don’t need a constant to convert into units (yet), so the final version of the formula is just
and all I had to do was calculate the travel time between every city on the map (all 98 of them).
I looked at how to do this using the hex map. I tried a lot of things but eventually I had to admit that the hex map simply wasn’t good enough. Forests and especially rivers did not follow hex sides and trying to encode them as side data ballooned. Eventually I realised that “hexpath” would have to be come “pixepath”, and the map would have to be some sort of bitmap image where each pixel was given one and only one terrain value.
2.1 A Star is born, then dies, is reborn, and finally discarded
I had been mulling this path finding idea for a while. I have written a few chess playing programs over the years, including a Dragon Chess written in M68000 assembly, and had been struck by the whole idea of quickly finding a move, and then progressively trying to find a better move. If the first “guess” move is sensibly chosen then the search time is drastically improved as candidates can be discarded early.
What, I thought, if we took a direct line from Point A to Point B over a map as a first guess, and then tried to refine it from there?
I constructed a test map and gave it a go. Well, to cut a long story short, it didn’t work. Looking back, I was gradually approaching the correct answer but my biggest problem was actually the direction of travel. Going from start to finish, my algorithm was constantly tripping over itself because the square it had “come from” at each step was not itself in a resolved and final state so it ended up looping over and over again. Adding flags didn’t help as that left the previous square as an unknown, preventing any objective early cutting out of paths by comparing them to the first guess.
I gradually started peeking at the Internet for help and found the A* algorithm. This is based on Dijkstra’s algorithm and like his it starts at the end and works backwards. Since the search starts with an objectively completed square (the destination, who’s cost is by definition known to be zero), it avoids the problem of tripping over its own tail and can always complete.
So I redid the code to use A* and things were good. For a while.
As it turns out, A* is a very fast way to find the distance between two points. But to find the distance between 97 points and a 98th, it’s not so hot. In my earlier code I had cached a lot of data in the hope of re-suing it, but A* doesn’t do that, so each run through starts from nothing again. For my code, once there were about 7 cities on the map, A* was getting slow.
Once I switched from a small test map to the map included in the code, which is 1807x1349 (8px = 1 mile), with lots of terrains, A* died a death. Going back to Dijkstra’s original algorithm, I realised that it in fact caches the whole map. Once Dijkstra’s has run once the output is the cost of moving from any point on the map to your chosen city. This means that finding the route from Thunderhold to CSIO takes 3 minutes - much longer than A* - but those three minutes also get you the distance from every other city and point on the map. Over all, this is a huge advance over A*.
2.2 Drunken Sailors, not Bee-lines
The first runs with the code generated trade routes all right. But they didn’t look very realistic. Partly this is because Dijkstra’s algorithm is known to behave slightly odd on a grid like a bitmapped image, but also because the transition between two pixels of light wood, or between light wood and open plain, always costs the same. So the trade routes were all made of horizontal, vertical, or 45° lines.
Adding a small pseudo-random factor to the cost of each square had a much larger effect than I had expected and the routes now look quite good, although not perfect.
2.3 Plains, Boats, and Roads
The next problem was that everything went by boat as far as possible. It’s certainly true that river and sea trade were extraordinarily important for mediaeval trade and one thing that modern people really don’t appreciate as they fly along the motorway at 70+mph is the humble bridge.
Until the 13th century, Britain had a massive shortage of bridges over rivers. If you have a one-ton cart being pulled by a couple of horses, even quite a small stream was an obstacle. If you were using oxen it was even worse as their short legs meant they would drown in a stream that a man could probably wade across.
So, yes, rivers should be important but they were insanely so when I first started to add significant numbers of towns to the map. The solution was to think more about what was being modelled: bulk goods.
One does not simply throw a ton of goods onto a barge and demand to be taken to
Modor Modron. You generally have to wait for the tide, the ship to be ready, perhaps for other goods to be loaded up etc. So there’s a delay. There’s also a delay at the other end, albeit a smaller one.
Similarly, where an adventuring party might simply build a raft and enter a river or even the sea almost anywhere, if they needed to, 10cwt of barley needs something more sophisticated. So, rivers became a barrier again, except at settlements. And at settlements, the assumption is that on average goods set off on the boat/ship/barge, the day after they arrive, and 6 hours are needed to get unloaded and underway at the other end.
Cobbling together transport is still possible but it’s madly expensive. Similarly, switching from or to river transport at a ford can be done but it takes a week.
Finally, there is an assumption that the boats in question are quite small and do not handle the larger swell of the open sea as well as they do the more sheltered areas near the coast, so movement rates for the former are reduced. At the moment, I’ve defined (using the map) “open sea” to be anywhere more than 5 miles from any coast.
Movement aside from the special delays for transshipping is defined using D&D scaled inches so that it’s easy to relate to. Normal overland movement in D&D is 2xMv. So, a move rate of 12“ translates to 24 miles per day. I’ve pre-calculated the 2x part in order to allow some finer-grained rates as shown in the code snippet below:
\ These values are effectively 2 x the normal D&D move rates +terrain impassible infinite impassible self! 32 " opensea \ slightly more risky, so avoid if possible 18 " city 48 " coastal 18 " plains 9 " woods 24 " roads 12 " ltwoods 9 " hills 6 " wdhills 1 " mts 1 " swamp 6 " desert 4 " scrub 6 " rough 30 " river 12 " ford 1 " jungle 4 " snow
I’ve not used snow yet. Note that the order of these terrains matches, and defines, the code used in the bitmap, so impassible is zero, open-sea is 1, city is 2 etc. When the program starts up it displays the combined movement table, which looks like this at the moment (probably best in the print-friendly version):
These costs are scaled to the 1px=1furlong of the bitmap. Notice that it’s not symmetrical: going from city to river costs 3840 movement points, and from river to city costs 640.
When considering these movement rates bear in mind that they’re for a horse-drawn wagon when on land.
2.4 Hard Border
The biggest limitation of what I’ve done so far is, of course, the map edge. The results below all assume that there is nothing beyond the map, including the western edge where of course the City State of the World Emperor lies.
2.5 Moving House
Beyond adding in a “wooded hills” terrain in a couple of places, the main changes I made to the map was to move some of the towns to more logical places. I never moved any outside of their own hex but, for example, Seasteadholm was moved to the coast instead of being a couple of miles inland. I assume the cartographer had to fit the symbols into the map and there wasn’t always room when there were also wood’s rivers, and coastal cliffs to show. Similarly, if a settlement is elven and there are woods in the hex, I moved them into the woods at least a bit.
2.6 Here Don’t Be Dragons
The biggest lack of this iteration of the code is the lack of monsters and castles. In some way, both of these should affect trade. Both are given in the guidebooks but their effect must be based at least partially on movement - a group of ogres three miles away across water is unimportant, while the same group by the side of a road is going to have an impact on trade. Castles may reduce the effect of monsters, but may also impose their own tolls.
Given that the 98 towns require something like 5hrs to analyse at the moment, this is going to have to wait.
3 Other Factors
Once the raw data was calculated, giving a basic figure for the trade between two settlements, a couple of other factors were added in which Reilly probably didn’t spend much time on: race, alignment, and civ (tech) level.
The race relations were based on the tables in PHB and DMG with some fiddling to join them together, as well as the addition of balrogs - a feature of the wider CSIO. The letters used in the game (P, G, T etc.) were mapped to specific multipliers (100% for prefer-ed,; 32% for hated; 10% for feared, a new category).
100 constant p 95 constant g 86 constant t 71 constant n 55 constant a 32 constant h 10 constant f \ dw el gn he hb ho hu gl go og or ba p , a , g , n , g , h , n , h , h , h , h , f , \ dw dwarf a , p , t , g , t , a , n , a , a , h , h , f , \ el elf g , t , p , t , g , h , n , h , h , f , h , f , \ gn gnoll n , p , t , p , n , a , t , a , a , h , h , f , \ he half-elf g , g , t , n , p , n , n , f , h , f , f , f , \ hb hobbit h , a , h , a , n , p , t , n , t , g , h , g , \ ho half orc n , n , n , t , n , n , p , a , a , h , h , f , \ hu human h , h , h , h , h , h , a , p , a , g , t , g , \ gl gnoll h , a , h , a , h , t , a , a , p , h , n , g , \ go golin f , f , h , f , a , t , t , t , a , p , t , n , \ og ogre f , f , h , h , a , g , t , n , t , g , h , g , \ or orc h , f , h , f , n , g , t , n , g , n , g , p , \ ba balrog
Since the race relations are not symmetrical, they’re calculated for each side of the trade and combined, so that if trade occurs between orcs and goblins the overall modifier is .95*.71=67.45% of normal.
Alignment is handled the same way but the percentages were loosely based on the loyalty modifiers in the DMG. On that note, I resolved the question about “1 step, 2 steps, 3 steps” by ruling that changing any letter to N was one step, but that someone at N could move to any alignment in a single step. So LG->LE is two steps (LG-LN->LE) but LG to CE is three (LG->NG->N->CE). Fudge-a-rama.
create aligntradetab \ N LG NG CG CN CE NE LE LN 85 , 100 , 85 , 80 , 75 , 65 , 70 , 90 , 95 , \ N 70 , 100 , 85 , 65 , 50 , 30 , 35 , 75 , 95 , \ LG 85 , 100 , 85 , 80 , 60 , 50 , 55 , 75 , 80 , \ NG 70 , 85 , 85 , 80 , 75 , 50 , 35 , 55 , 60 , \ CG 85 , 85 , 70 , 80 , 75 , 65 , 55 , 75 , 80 , \ CN 70 , 65 , 50 , 65 , 75 , 65 , 70 , 75 , 60 , \ CE 85 , 85 , 70 , 65 , 60 , 65 , 70 , 90 , 80 , \ NE 70 , 85 , 50 , 45 , 40 , 50 , 70 , 90 , 95 , \ LE 85 , 100 , 70 , 65 , 60 , 50 , 55 , 90 , 95 , \ LN
Generally, people trust Lawful and Good -types most, and Neutrals are suspected a bit by everyone.
3.3 Civilisation Level
Each town is given a civ rating in the guidebooks and I’ve modelled this by simply them together, adding 1, and then multiplying trade volume by that. So a civ 8 trading with a civ 5 gets a 14x multiplier while a civ 9 trading with civ 9 gets an 19x multiplier.
The median civ rating seems to be about 5, so x11 (5+5+1) is the “normal” rating.
4 The Results
4.1 Trade Routes
This was the original target question: what are the trade routes? The current base map is (note: these maps are not opening when clicked on but if you select "Open in new tab" you should get the full-res versions):
Overlaying trade routes, with the boldness of the route being proportional to the amount of trade, gives this (open sea removed for clarity:
Figure 1: Graduated Trade Map
Here’s the same map but with the routes shown at the same boldness regardless of the amount of traffic:
Figure 2: Un-Graduated Trade Map
The next map is one that relates mostly to von Thünen’s model a bit more. This is a graduated tint overlaid on the map and centred on the CSIO itself, each step from light to dark indicating one day’s travel to the city.
I’ve pushed the bounds of copyright here to allow some of the original map to show through under my coloured version and the tint.
Figure 3: Days Travel To CSIO
It’s worth looking at this map for a while and visualising how much you know about places that are 5½ days travel away from you - the distance that Thunderhold is from CSIO. Assuming that you can think of anywhere that would take 5½days to get to in the modern world!
The final map is just for interest and superimposes a map of Kent on Wilderlands map 1 to show the scale. Basically, each Wilderlands map covers an area of 24.3 million acres (38088m²), which is about ¾ of the size of England.
Figure 4: Kent for scale
4.2 Trade Volumes
Trade is measured in arbitrary units for now and the program captures two main numbers for each settlement: the amount of external trade it engages in itself, and the amount of trade which passes through it on the way to somewhere else.
Since each town has a listed population we can translate these numbers into a measurement of wealth, even if we don’t have a specific ratio to convert it into gps. Another obstacle to making too much of these numbers - creating a measure of GDP - is that these numbers are all for external trade and don’t capture anything at all about internal trading within each town.
Taking tax on passing trade at a rate of 5% (1 shilling per pound) and adding it to the main trade figure gives the following table ordered by total income per person:
Re-arranging the table to give the top 20 cities by raw trade gives us:
There’s not much to say about the City State itself. As expected, it is the largest economy and it draws in some trade from basically everywhere on the map. The biggest trading partner is Warwick at 26.2% of all trade. Here’s the whole list, down to those with 0.1% share:
Yes, so. Warwick. No one ever talks about Warwick, but it’s one of the biggest cities in the whole setting, not just Map 1. Bigger than Tarantis, bigger than Valon by miles. It dominates the north coast and the only reason it is not more important as a trading partner is that the map ends just north of it.
As it is, it has more trade per person than CSIO and has a higher civ rating too.
Much smaller than Warwick, or even Ossary, the model used doesn’t, I think, give Modron due consideration for potential tax collection from passing vessels but since they don’t literally pass through the town the program doesn’t catch them. Even so, it has the second highest ratio of direct trade to population, after Darkfield, and on that measure the citizens are more than twice as wealthy as those of the CSIO.
|City||% Modron Trade|
- Pareto Curves
The question naturally arises from the above observation as to how the uppermost members of society compare between the CSIO and Modron, given that the (external trading) economy of the former is 7¼ times the latter.
If we use an 80/20 split (80% of wealth is owned by 20% of people) then we get the top 20% of Modronites are sharing 47863 between them, which is 129.7 units each. The same calculation for CSIO gives 348705 to the top 20%, which is 87. When looking at percentages this disparity holds, but for the CSIO the number of people sharing that wealth is much higher and the true picture comes out when looking at it from that PoV.
So when we look at the top 20 people in each place, the difference between the two cities’ elites is clearer. For Modron these people represent 1.6%, whereas for the CSIO they represent 0.1%. The 20 Modronites have 1695 units of wealth each, the City Staters average 8405 units each.
Ultimately, the top guy in Modron can expect to control 22424 units of trade while the Overlord grabs 111204 (assuming that the Overlord is as content to share as Anoethin is).
I’ve glossed over many questions here, not least of which are what slope to use for the Pareto calculation and how applicable it is to very small numbers of people in autocratic societies. Not to mention that populations listed in the guides are for able-bodied men of fighting age, not full populations. Perhaps "top families" would be a better way of looking at it.
Although Ossary is big and technically advanced (civ 8), its alignment of CE costs it a lot of trade. Still, it dominates the southern area to a degree which can only increase once Map 2 is added. The largest city there, Antil, is just over ⅓ of the size of Ossary and somewhat backward with a civ rating of 4.
|City||% Ossary Trade|
Being on the road to CSIO as well as being physically close to it gives Darkfield a huge boost without being too incompatible on race, alignment, or civ.
Like Darkfield, Haghill is near the city and gets a bigbump from that despite being small and undeveloped.
Sticklestead is another large settlement that doesn’t get much of a look in, although an official scenario dealing with the area did come out in 2010(!). Bigger than Modron, it’s important because it allows access to the river and thereby to the sea, CSIO, and Warwick. I’ve also given it a bridge and a ford over the local rivers.
5 So what?
What to do with all this information? Well, the trade route maps show, for example, that Wormshead point is a good place to go a-pirating, and a place to send patrols to prevent it. There’s a line of small islands south of Croy which might make interesting bases for this sort of activity too, if the keyed encounters are not enough to put the players off.
The same goes for the land, with various crossroads apparent where PCs can prey on caravans, hire on to protect them, or where the DM can place inns or similar out-of-town bases.
PCs hired to locate lost cargoes or kidnapped merchants may be able to use their wits to learn of likely places to start a search.
The major cities will have rivalries and intrigues aimed at getting an economic advantage. Guilds from the cities will do likewise.
The information gives some idea of how likely it is to be able to learn something by locating a native traveller. So, finding someone from Warwick won’t pose too much trouble in most locations near the sea but finding people from Tegal to ask about its manor might be hard.
Even Thunderhold has only a 3.8% share of the City State’s trade.
There will be other uses, but for now I need to look at making the code multi-threaded so that I can hope to tackle adding on at least Map 6 and see what that does to the trade routes to the west.
All the Forth code is on Github (https://github.com/tworthington/csiotrade)