Settlers 2, Pathfinding and Writing Code for Fun!
Last week or so I dug up something very amazing on The Piratebay. Someone packed up good old DOS classics into a Dosbox wrapper for Mac OS X, so I could start and run those games in a window on my Mac. Simply amazing. So I started up Settlers II, one of the best games I've ever played. (Don't gimme any crap about pirating games! I own this game. And the expansion. What do you think have I been doing during my childhood?
)
So for all that don't know the game here's Settlers II in a nutshell: every player starts out with a headquarter, a limited amount of building materials, goods, tools, settlers with different skills and a small strip of land. The surroundings offer everything you need to build up your small empire: woods that can be cut down by lumberjacks, granite that can be cut by stone cutters, mountains that offer coal, ore and gold and flat land that can be used to grow crops. On of the major challenges of this game is to get all the production chains right: let's take for example a lumberjack. A lumberjack cuts down trees. The logs then needs to be transported to a sawmill where they get cut into handy boards. (Picture 1 shows such a production chain.) These boards in turn then need to get to a stock or to construction sites. And if you don't build a forester your lumberjack will run out of trees very soon. That was one of the easier production chains. Let's look at something more sophisticated: production of meat. You'll start of with a farm that grows crops. Then you need a pigfarm that takes the crops grown by the farm and water from a well to breed pigs. And finally, to get to your tasty meat, you'll need a slaughterhouse. So, all in all, getting those production chains right tricky and very rewarding. Nothing better than seeing wares running smoothly form source to destination (at least for me
).

Picture 1: A production chain for lumber. On the bottom left there is the forrester. The guy living in that building just keeps planting trees. The building at the top left and to the right are lumberjacks.They cut down trees. Those trees then get transported to the building to the top right, the sawmill where they get cut up.
The other big challenge, and actually the reason why I'm blogging about this, is the way system. All the production facilities mentioned above are connected by a road system. Each of those buildings has a flag in front it and whenever a building "finishes" producing an item, the item gets dropped at the flag (I won't go into the hygienically implications of dropping food on flag on a dusty road... ). Connected to the flag is a road that leads to another flag and standing on that road is a carrier, a poor guy who's job it is to just carry stuff from the one flag to the other flag. See Picture 2 to get a better understanding. So eventually this road leads to another building that actually needs what has been produced. In the picture below that would be the small pig on the flag to the right that needs to get to the slaughterhouse to the left (Hey, it's biological after all!).
So getting the way system right is crucial to your success in that game. If your roads are too long, it will take forever to complete things. If you don't set enough flags, the actual capacity of a given road segment will drop - after all there is only one guy standing between two flags and he can carry only one item at once (an exception are the donkeys that you get after a road has been in heavy use but that still only gives you two items per segment).
Now, you have an understanding of what that game is about. If you don't, get yourself a copy and play it a bit. But be careful, it's addictive.
So while I was playing a bit I started to wonder, how all this worked. How do wares get routed from one flag to another flag. How to flags eventually reach their destination? How is ensured that wares don't run in circles? How is ensured that best possible route is taken? All those thoughts kind of reminded me of my excellent algorithms and data structures lessons at the Hochschule München, where graphs and different algorithms on graphs where a big subject. So I got really curious how to implement something like that. After all, at university we implemented a lot of the data structures and algorithms but never for a "real" problem.
Later that night I started up Eclipse and got churned out some code to actually represent a hexgonal map (Settlers 2 uses a hexagonal grid as opposed to most modern games that just use isometric rectangular maps), render out that map to the screen and some classes to represent flags and roads. And then the fun started...
My first goal was to implement a pathfinding algorithm that actually finds a good route from one given hexagon to another hexagon. Sounds easy but is a really hard problem. There are a couple of algorithms out there that actually solve that problem but I decided to go with the simplest one, Dijsktras algorithm that is guaranteed to produce the best solution. However implementing that algorithm wasn't as easy as I anticipated. My first test run produced some rather... unexpected results:

Picture 3: Pathfinding done wrong. The goal was to find the shortest possible route from the one green flag to the other green flag... The gray zig-zag line is the path my implementation found...
Obviously that was not the best possible solution! Eventually it took me a couple of hours to get my implementation right. But then I got it right:

Picture 4: Pathfinding done right! Made the paths red in that screenshot for better visibility. Note how the red paths connecting the green flags are the shortest possible.
My conclusion after a couple of hours trying to get that right: It was a lot of fun and kudos to the developers of Settlers 2! I did not spend too much time on that but it became quickly obvious that building a game as "simple" as this old DOS game is all but easy. Building even simple pathfinding imposed quite a challenge on me. Building a whole game like that seems one hell of a task...
The next step is now to build a pathfinder that is actually aware of terrain (you can't build roads on water!) and won't allow to cross roads. With that in place i can finally start to play around with the actual routing of goods in this graph. The technical more adept might argue that I actually don't need all the stuff that I wrote so far to calculate some spanning trees on a graph. And they're right. But otherwise it wouldn't be as much fun!
Depending on how much spare time I have I'll keep playing around with this and keep you posted...


March 18th, 2009 - 18:19
You convinced me… gonna play now!
March 23rd, 2009 - 19:42
can you post the source? might be cool to port this to AS3 and see how it performs…
March 24th, 2009 - 04:33
The stuff I wrote is in Java. Right now I’m splitting up the project in several sub projects (api, impl, swing-ui) to get a clear separation. Then I could publish it… Anybody interested to see that as an open source project?
May 15th, 2009 - 07:19
I would be interested in looking at the source. Curious about how you draw the hexagons and the actual pathfinding routines.
Did you draw the hexagons as lines (1 line with multiple points, or multiple lines) or did you use tiles?
Its ok if the code in in java, I’m familiar with it. My current project is being done in objective C, and on a Mac as well
May 15th, 2009 - 16:22
Hey Adam,
I’ve setup a project on github a couple of weeks ago. All the code is there, so check it out: http://github.com/ilikeorangutans/s2/tree/master
The code to render out the hexagons is located under ui/swingui
Currently I’m using just regular polylines to draw the hexagons. Not very pretty but I didn’t have any time to switch that to real tile based rendering.
What kind of project are you working on? Settler-like game?
May 18th, 2009 - 17:31
Thanks Jakob for the link to the source.
The project I am currently working on is a Turn Based Strategy.
I have some code in objC that does tiling and handles coordinates if you are interested. I am switching to OpenGL for my rendering, hence my question on how you went about drawing your hexagons, since I will more then likely be using GL_LINES to draw the hexagons (that way I can toggle displaying them).
May 18th, 2009 - 18:18
Hey Adam,
I thought about using OpenGL too, but eventually you want to render out bitmap tiles instead of simple lines. But I guess OpenGL is a good choice for that too. Do you have a source repository?
Cheers,
Jakob
February 18th, 2010 - 20:37
Having been thinking about trying to make a Settlers 2 clone using Javascript, I wondered upon this… and the first thing that struck me when looking at your post is the time it took you to do this when you didn’t even take into account steepness, which the original does when computing distance (but there again, I guess you can calculate the normalized distance once per road, and recompute as needed).
February 18th, 2010 - 20:42
Hey Geoffrey,
wow, you wanna implement Settlers in JavaScript? Seems like one hell of a task.
The steepness would be rather easy to incorporate i guess. There’s a function that estimates the ‘cost’ of a path segment that is being used by the algorithm. Right now I’m using uniform cost for every segment, but changing it to return something based on the height difference wouldn’t be hard.
Cheers,
Jakob
February 19th, 2010 - 10:33
Yeah, it seems like a fun, somewhat insane challenge. However, now I remember what it was, it wasn’t height that was causing issues (as as you say, changing the effective distance is trivial), but rather the issue of actually routing items: you don’t want a pure path-finding algorithm, but also you want to do something magic (I’m not entirely sure about the S2 behaviour) based upon the number of items at each flag. Getting that right is going to be needed to try and get a decent implementation, and working out what the behaviour has to be is certainly going to be non-trivial.
February 19th, 2010 - 12:58
I like the challenge. How are you going to render and paint? Using canvas?
I thought about the routing as well, after all it was the idea that made me start this project (unfortunately I don’t have time to commit right now). IMHO it boils down to building a minimum spanning tree through the graph. Using this, you can identify a good path; however if, as you say, flags fill up, routing gets trickier. This could be solved by using the number of items on the flags as additional cost?