For a while now, I've been looking for a method to randomly generate a map of fake (but realistic-looking) countries. Since I haven't had much success yet (even after asking about it online once already), I thought I'd ask this community now.
Here are the principles that I want the final map to follow:
- Borders should be somewhat crinkly (fractal dimension around 1.1).
- Countries should be somewhat disparate in size (ratio of areas of largest and smallest countries perhaps around 1.5-3; I'm not as sure about the specifics of this one, but I can definitely tell when it looks wrong).
- Countries should be relatively contiguous and isthmus-free.
Code: Select all
import golly as g
# starts from initial pattern
NUMITERATIONS=int(g.getstring("How many iterations?","4"))
DENSITY=int(g.getstring("How dense is the soup (in %)?","25"))
MARGIN=int(g.getstring("How wide are the margins?","16"))
g.setrule("B5678/S45678")
g.autoupdate(True)
for i in range(NUMITERATIONS):
VIOLINIST=g.getrect()
CELLIST=g.getcells(VIOLINIST)
g.new("")
g.setstep(4)
g.select([-MARGIN,-MARGIN,2*(VIOLINIST[2]+MARGIN),2*(VIOLINIST[3]+MARGIN)])
g.randfill(DENSITY)
g.fit()
# eliminate chance islands
CHANGES=""
while True:
# run to stabilization
THISHASH=g.hash(g.getselrect())
while True:
g.step()
NEXTHASH=g.hash(g.getselrect())
if THISHASH==NEXTHASH:
break
THISHASH=NEXTHASH
# check for chance islands
if g.empty():
g.reset()
break
else:
# futility check (very rare but can happen)
if CHANGES==g.getcells(g.getselrect()):
break
CHANGES=g.getcells(g.getselrect())
g.reset()
g.putcells(CHANGES,0,0,1,0,0,1,"xor")
# xor-paste in original pattern at double scale
g.putcells(CELLIST,-2*VIOLINIST[0],-2*VIOLINIST[1],2,0,0,2,"xor")
g.putcells(CELLIST,-2*VIOLINIST[0],1-2*VIOLINIST[1],2,0,0,2,"xor")
g.putcells(CELLIST,1-2*VIOLINIST[0],-2*VIOLINIST[1],2,0,0,2,"xor")
g.putcells(CELLIST,1-2*VIOLINIST[0],1-2*VIOLINIST[1],2,0,0,2,"xor")
# run to stabilization
THISHASH=g.hash(g.getselrect())
while True:
g.step()
NEXTHASH=g.hash(g.getselrect())
if THISHASH==NEXTHASH:
break
THISHASH=NEXTHASH
g.select([])
However, I haven't been as successful with multiple countries fitting together. Here are some types of rules that I've tried:
- Multi-state rules where each individual cellstate follows B5678/S45678: size of countries becomes way too disparate with few states; simulation gets way too slow with many states.
- Rules where seeds form and grow but resist merging (e.g. B15-knqr6a78/S4-nwz5-kr678): this creates a rather large size disparity between regions.
- Rules where cells naturally settle into a skeleton-like structure (e.g. R20,C0,M1,S167..646,B604..877,NM): while the countries-to-be are placed rather well, their borders are too smooth, and there's even a slight chance of border failure.
- Rules based on crystallographic defects (e.g. B2ce3cn4acknwy5aekry6akn7e/S1e2aei3ciny4jknqry5-cjny6k7c, possibly interesting in its own right): while the result is four-colorable (colors correspond to parities of x- and y-coordinates), it's not very realistic, due to two adjacent regions of the same color effectively being considered as one.
- Multi-state rules where each individual cellstate follows the same explosive rule: this has problems similar to the ones in the other multi-state rule, except that the problem with too many cellstates is that the seeds won't grow.
- Voronoi diagrams: these create a pretty good starting point, but their borders are always completely and unrealistically straight.
- Mudcracks: modeling these is only easy via the real thing (which takes a while), and suffers from the straight-borders problem.
- DFS maze-generation algorithm from multiple starting points: this frequently generates one-cell-thick isthmuses.
- Prim's algorithm from multiple starting points: many countries generated this way seem to be long and skinny.
- Kruskal's algorithm from multiple starting points: borders seem to be a bit too crinkly.