import random, sys, os from PIL import Image class CellMap: initial = [] genmap = [] def __init__(self, height=None, width=None, seed=None, death=None, birth=None, reps=0, out=None, color=None, chunky=None, treasure=None): self.height = height if height != None else 0 self.width = width if width != None else 0 self.seed = seed if seed != None else 0 self.death = death if death != None else 0 self.birth = birth if birth != None else 0 self.reps = reps if reps != None else 0 self.out = out if out != None else False self.color = color if color != None else False self.chunky = chunky if chunky != None else False self.treasure = treasure if treasure != None else False self.id = filename() @property def height(self): return self.__height @height.setter def height(self, height): self.__height = int(height) if int(height) > 0 else 0 @property def width(self): return self.__width @width.setter def width(self, width): self.__width = int(width) if int(width) > 0 else 0 @property def seed(self): return self.__seed @ seed.setter def seed(self, seed): self.__seed = int(seed) if int(seed) > 0 else 0 @property def death(self): return self.__death @death.setter def death(self, death): self.__death = int(death) if int(death) > 0 else 0 @property def birth(self): return self.__birth @birth.setter def birth(self, birth): self.__birth = int(birth) if int(birth) > 0 else 0 @property def reps(self): return self.__reps @reps.setter def reps(self, reps): self.__reps = int(reps) if int(reps) > 0 else 0 @property def out(self): return self.__out @out.setter def out(self, out): self.__out = bool(out) @property def color(self): return self.__color @color.setter def color(self, color): self.__color = bool(color) @property def chunky(self): return self.__chunky @chunky.setter def chunky(self, chunky): self.__chunky = bool(chunky) @property def treasure(self): return self.__treasure @treasure.setter def treasure(self, treasure): self.__treasure = bool(treasure) def generateFullMap(self): """ Puts everything together. """ self.createMap() for _ in range(self.reps): self.smoothMap() if self.out: self.createImage() else: self.printScreen() def resetMap(self): """ Resets the map to its initial state, allowing the user to experiment with death/birth limits and number of repetitions on a single map. """ self.genmap = list(self.initial) def createMap(self): """ Initializes an x by y grid. x is width, y is height seed is the chance that a given cell will be "live" and should be an integer between 1-99. If True is equivalent to "wall", then higher seeds make more walls. """ if self.__height == 0 or self.__width == 0 or self.__seed == 0: print("Height, width, and seed must be set before creating a map.") print("Current values: height: {}, width: {}, seed: {}".format(self.height, self.width, self.seed)) return y = self.height x = self.width seed = self.seed new_map = [] for j in range(y): new_row = [] for i in range(x): new_row.append(True if random.randint(1,99) <= seed else False) new_map.append(new_row) self.initial = new_map self.genmap = new_map def smoothMap(self): """ Refines the grid. """ if self.death == 0 or self.birth == 0: print("The 'death' limit is currently {} and the 'birth' limit is {}.".format(self.death,self.birth)) print("Smoothing with the 'death' or 'birth' limit set to 0 is not recommended.") print("Do you want to proceed? (y/N) ", end="") cont = input().strip() if cont.lower() != "y": print("Aborting.") return d_lmt = self.death a_lmt = self.birth new_map = [] for j in range(len(self.genmap)): new_line = [] for i in range(len(self.genmap[j])): x, y = i, j n_count = self.countWalls(x, y) if self.genmap[y][x]: # It's a wall. if n_count < d_lmt: # It has too few wall neighbors, so kill it. new_line.append(False) else: # It has enough wall neighbors, so keep it. new_line.append(True) else: # It's a path. if n_count > a_lmt: # It has too many wall neighbors, so it becomes a wall. new_line.append(True) else: # It's not too crowded, so it stays a path. new_line.append(False) new_map.append(new_line) self.genmap = new_map def countWalls(self, x, y): count = 0 for j in range(-1,2): for i in range(-1,2): n_x, n_y = x+i, y+j if i == 0 and j == 0: continue if n_x < 0 or n_x >= len(self.genmap[j]) or n_y == 0 or n_y >= len(self.genmap): # The target cell is at the edge of the map and this neighbor is off the edge. # So we make this neighbor count as a wall. count += 1 #pass elif self.genmap[n_y][n_x]: # This neighbor is on the map and is a wall. count += 1 return count def printScreen(self): wall = "II" path = " " for line in self.genmap: print("".join([wall if x else path for x in line])) print() def createImage(self): x, y = len(self.genmap[0]), len(self.genmap) if self.chunky: true_x, true_y = x*2, y*2 else: true_x, true_y = x, y img = Image.new("RGB",(true_x,true_y),(0,0,0)) lst = [] # Walls are black by default c_wall = [random.randint(0,255), random.randint(0,255), random.randint(0,255)] if self.color else [0,0,0] # Paths are white by default c_space = [255-x for x in c_wall] if self.chunky: for line in self.genmap: for _ in range(2): for val in line: for _ in range(2): lst.append(tuple(c_wall) if val else tuple(c_space)) else: for line in self.genmap: for val in line: lst.append(tuple(c_wall) if val else tuple(c_space)) img.putdata(lst) if not os.path.exists("maps"): os.makedirs("maps") fn = self.id i = 0 while os.path.exists("maps/{}.png".format(fn)): i += 1 fn = self.id + "-" + str(i) img.save('maps/{}.png'.format(fn)) print("Saved maps/{}.png".format(fn)) def printArray(self): print("[",end="\n") for line in self.genmap: print("\t{},".format(line)) print("]") def filename(): hexes = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] fn = [] for _ in range(16): fn.append(random.choice(hexes)) return "".join(fn) def parseArgs(args): flags = { "--height" : 20, "--width" : 20, "--seed" : 45, "--death" : 4, "--birth" : 4, "--reps" : 2, "--out" : False, "--color" : False, "--chunky" : False, "--treas" : False, } for flag, default in flags.items(): if flag in args: if flag == "--out": flags["--out"] = True elif flag == "--color": flags["--color"] = True elif flag == "--chunky": flags["--chunky"] = True else: flags[flag] = args[args.index(flag) + 1] return flags def main(args): flags = parseArgs(args) my_map = CellMap(flags["--height"],flags["--width"],flags["--seed"],flags["--death"], flags["--birth"],flags["--reps"],flags["--out"],flags["--color"], flags["--chunky"],flags["--treas"],) my_map.generateFullMap() if __name__ == "__main__": main(sys.argv)