Randomly generating terrains

… aka “When the Creator misplaces a parenthesis”. :)

So my first attempt to write a program to generate random but pleasing landforms for my Sim on a Stick did not go quite as expected.

When the Creator God misplaces a paren...

Bit spikey, for instance.

But then I found a misplaced parenthesis! And things got better.

Ah, much better

I think I am liking the algorithm…

Landforms from the RNG

For the curious, here is the basic (recursive, self-similar) routine, in everyone’s favorite language: Python. (Squished down to fit in the weblog here, not guaranteed to compile as-is.)

def fill_in_terrain(t,lowx,lowy,maxx,maxy):
   ''' Takes the input terrain, where the low-by-max '''
   ''' corners are already filled in, and fills in '''
   ''' everything inside those corners, by the '''
   ''' Magic of Recursion. '''
   if maxx-lowx<2: return t
   if maxy-lowy<2: return t
   xmid = int((lowx+maxx)/2)    
   ymid = int((lowy+maxy)/2)
   hscale = (maxx - lowx) * HSCALE
   # first the corners
   if t[lowx][ymid] is None:
     t[lowx][ymid] = (t[lowx][lowy] + t[lowx][maxy]) / 2 
       + hscale - math.floor(2*hscale*random.random())
   if t[maxx][ymid] is None:
     t[maxx][ymid] = (t[maxx][lowy] + t[maxx][maxy]) / 2 
       + hscale - math.floor(2*hscale*random.random())
   if t[xmid][lowy] is None:
     t[xmid][lowy] = (t[lowx][lowy] + t[maxx][lowy]) / 2 
       + hscale - math.floor(2*hscale*random.random())
   if t[xmid][maxy] is None:
     t[xmid][maxy] = (t[lowx][maxy] + t[maxx][maxy]) / 2 
       + hscale - math.floor(2*hscale*random.random())
   # then the center
   if t[xmid][ymid] is None:
     t[xmid][ymid] = (t[lowx][ymid]+t[maxx][ymid]
                     + t[xmid][lowy]+[xmid][maxy])/4 
                     + hscale - math.floor(2*hscale*random.random())
   # and recurse on the four quadrants
   t = fill_in_terrain(t,lowx,lowy,xmid,ymid)
   t = fill_in_terrain(t,lowx,ymid,xmid,maxy)
   t = fill_in_terrain(t,xmid,lowy,maxx,ymid)
   t = fill_in_terrain(t,xmid,ymid,maxx,maxy)
   return t

def get_terrain(x,y):
   ''' returns an [x][y] array of floats representing a terrain; '''
   ''' range unpredictable '''
   ''' x and y ought to be powers of two, for best results.  '''
   ''' oh, and equal I suppose '''
   answer = [ [None for a in range(y+1)] for b in range(x+1) ]
   answer[0][0] = 0
   answer[x][0] = 0
   answer[0][y] = 0
   answer[x][y] = 0
   answer = fill_in_terrain(answer,0,0,x,y)
   return answer

Fun that all these pretty hills and things come out of that little bit of (also pretty) code…