#!/usr/bin/python import cgi import math, random import cgitb cgitb.enable() import math, random def get(l, index, default): if 0 <= len(l) <= index: return default return l[index] # terrain class class Terrain: name = "no terrain" character = "E" std_color = [0, 1.0, 0] color = [] hex_color = "" def __init__(self, row, column, elevation): if self.__class__ is Terrain: raise NotImplementedError("Terrain is an abstract class; don't \ create objects of this type directly") self.row = row self.column = column self.elevation = elevation self.color = [] for rgb in self.std_color: self.color.append(min(1.0, rgb + self.elevation / 5)) for rgb in self.color: self.hex_color += "%02X" % math.ceil(max(0, rgb * 255)) def html(self): return "" + self.character + "" # terrain types class Grass(Terrain): name = "grass" character = "." std_color = [0.2, 0.7, 0.2] def __init__(self, row, column, elevation): Terrain.__init__(self, row, column, elevation) class Ridge(Terrain): name = "a ridge" character = "-" std_color = [0.7, 0, 0] def __init__(self, row, column, elevation): Terrain.__init__(self, row, column, elevation) class Shrub(Terrain): name = "a shrub" character = ";" std_color = [0.6, 0.6, 0] def __init__(self, row, column, elevation): Terrain.__init__(self, row, column, elevation) class Tree(Terrain): name = "a tree" character = "#" std_color = [0.15, 0.6, 0.15] def __init__(self, row, column, elevation): Terrain.__init__(self, row, column, elevation) class Water(Terrain): name = "water" character = "~" std_color = [0.1, 0.5, 1.0] def __init__(self, row, column, elevation): Terrain.__init__(self, row, column, elevation) # cellular automaton def TotalisticAutomaton(code, line): nextline = [] for cell in range(len(line)): total = int(round(get(line, cell-1, 0) + get(line, cell, 0) + \ get(line, cell+1, 0))) nextline.append(code[total]) return nextline # core map functions def SeedElevationMap(width, height, code): random.seed() matrix = [[random.uniform(0, 2) for spam in range(width)]] for i in range(height): curline = TotalisticAutomaton(code, matrix[i]) curline.reverse() # compensates for left bias slightly? for j in range(width): if curline[j] < matrix[i][j]: curline[j] += random.random() elif curline[j] > matrix[i][j]: curline[j] -= random.random() matrix.append(curline) return matrix def SeedTerrain(width, height, code): random.seed() matrix = [[random.randint(0, 2) for spam in range(width)]] for i in range(height): matrix.append(TotalisticAutomaton(code, matrix[i])) return matrix def CreateMap(elevmap, terrain): map = [] for j in range(len(terrain)-1): map.append([]) for k in range(len(terrain[0])-1): if terrain[j][k] == 0: map[j].append(Shrub(j, k, elevmap[j][k]-1)) elif terrain[j][k] == 1: map[j].append(Grass(j, k, elevmap[j][k]-1)) elif terrain[j][k] == 2: map[j].append(Tree(j, k, elevmap[j][k]-1)) elif terrain[j][k] == 3: map[j].append(Water(j, k, elevmap[j][k]-1)) return map def CreateRiver(elevmap, terrain, buffer): nadir = elevmap[0].index(min(elevmap[0][buffer*5:len(elevmap[0])-buffer*5])) for i in range(len(terrain)-1): for j in range(buffer*2+1): try: terrain[i][nadir-buffer+j] = 3 elevmap[i][nadir-buffer+j] /= 2 except: break left = elevmap[i][max(0, nadir-buffer*2):nadir] left.reverse() for cell in left: if cell < 1: terrain[i][elevmap[i].index(cell)] = 3 else: break right = elevmap[i][nadir:min(len(elevmap[i]), nadir+buffer*2)] for cell in right: if cell < 1: terrain[i][elevmap[i].index(cell)] = 3 else: break try: nadir = elevmap[i].index(min(elevmap[i][nadir-1:nadir+1])) except: break # river went offscreen return terrain # the most famous totalistic automata: # code177 = [0, 2, 1, 0, 2, 0, 0] # code912 = [0, 1, 2, 0, 2, 0, 1] code2040 = [0, 2, 1, 0, 1, 2, 2] # my preferences: # code1760 = [2, 1, 0, 2, 0, 1, 2] code1878 = [0, 2, 1, 0, 2, 1, 2] # another neat one but a bit too dark: # code2120 = [2, 1, 1, 0, 2, 2, 2] # terrain = [[1 for spam in range(80)] for eggs in range(48)] elevmap = SeedElevationMap(80, 48, code2040) terrain = SeedTerrain(80, 48, code1878) terrain.reverse() # now it's the south slope terrain = CreateRiver(elevmap, terrain, 3) forest = CreateMap(elevmap, terrain) print "Content-Type: text/html" print print "

Wendy Automata's Forest

" for i in forest: line = "" for j in i: line += j.html() print line + "
" print ""