| @@ -0,0 +1,272 @@ | |||
| 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 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 = self.initial | |||
| 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 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) | |||