Python script to generate simple "dungeon maps"
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

CellMap.py 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import random, sys, os
  2. from PIL import Image
  3. class CellMap:
  4. initial = []
  5. genmap = []
  6. def __init__(self, height=None, width=None, seed=None, death=None,
  7. birth=None, reps=0, out=None, color=None, chunky=None,
  8. treasure=None):
  9. self.height = height if height != None else 0
  10. self.width = width if width != None else 0
  11. self.seed = seed if seed != None else 0
  12. self.death = death if death != None else 0
  13. self.birth = birth if birth != None else 0
  14. self.reps = reps if reps != None else 0
  15. self.out = out if out != None else False
  16. self.color = color if color != None else False
  17. self.chunky = chunky if chunky != None else False
  18. self.treasure = treasure if treasure != None else False
  19. self.id = filename()
  20. @property
  21. def height(self):
  22. return self.__height
  23. @height.setter
  24. def height(self, height):
  25. self.__height = int(height) if int(height) > 0 else 0
  26. @property
  27. def width(self):
  28. return self.__width
  29. @width.setter
  30. def width(self, width):
  31. self.__width = int(width) if int(width) > 0 else 0
  32. @property
  33. def seed(self):
  34. return self.__seed
  35. @ seed.setter
  36. def seed(self, seed):
  37. self.__seed = int(seed) if int(seed) > 0 else 0
  38. @property
  39. def death(self):
  40. return self.__death
  41. @death.setter
  42. def death(self, death):
  43. self.__death = int(death) if int(death) > 0 else 0
  44. @property
  45. def birth(self):
  46. return self.__birth
  47. @birth.setter
  48. def birth(self, birth):
  49. self.__birth = int(birth) if int(birth) > 0 else 0
  50. @property
  51. def reps(self):
  52. return self.__reps
  53. @reps.setter
  54. def reps(self, reps):
  55. self.__reps = int(reps) if int(reps) > 0 else 0
  56. @property
  57. def out(self):
  58. return self.__out
  59. @out.setter
  60. def out(self, out):
  61. self.__out = bool(out)
  62. @property
  63. def color(self):
  64. return self.__color
  65. @color.setter
  66. def color(self, color):
  67. self.__color = bool(color)
  68. @property
  69. def chunky(self):
  70. return self.__chunky
  71. @chunky.setter
  72. def chunky(self, chunky):
  73. self.__chunky = bool(chunky)
  74. @property
  75. def treasure(self):
  76. return self.__treasure
  77. @treasure.setter
  78. def treasure(self, treasure):
  79. self.__treasure = bool(treasure)
  80. def generateFullMap(self):
  81. """ Puts everything together.
  82. """
  83. self.createMap()
  84. for _ in range(self.reps):
  85. self.smoothMap()
  86. if self.out:
  87. self.createImage()
  88. else:
  89. self.printScreen()
  90. def resetMap(self):
  91. """ Resets the map to its initial state, allowing the user to experiment
  92. with death/birth limits and number of repetitions on a single map.
  93. """
  94. self.genmap = list(self.initial)
  95. def createMap(self):
  96. """ Initializes an x by y grid.
  97. x is width, y is height
  98. seed is the chance that a given cell will be "live" and should be an integer between 1-99.
  99. If True is equivalent to "wall", then higher seeds make more walls.
  100. """
  101. if self.__height == 0 or self.__width == 0 or self.__seed == 0:
  102. print("Height, width, and seed must be set before creating a map.")
  103. print("Current values: height: {}, width: {}, seed: {}".format(self.height, self.width, self.seed))
  104. return
  105. y = self.height
  106. x = self.width
  107. seed = self.seed
  108. new_map = []
  109. for j in range(y):
  110. new_row = []
  111. for i in range(x):
  112. new_row.append(True if random.randint(1,99) <= seed else False)
  113. new_map.append(new_row)
  114. self.initial = new_map
  115. self.genmap = new_map
  116. def smoothMap(self):
  117. """ Refines the grid.
  118. """
  119. if self.death == 0 or self.birth == 0:
  120. print("The 'death' limit is currently {} and the 'birth' limit is {}.".format(self.death,self.birth))
  121. print("Smoothing with the 'death' or 'birth' limit set to 0 is not recommended.")
  122. print("Do you want to proceed? (y/N) ", end="")
  123. cont = input().strip()
  124. if cont.lower() != "y":
  125. print("Aborting.")
  126. return
  127. d_lmt = self.death
  128. a_lmt = self.birth
  129. new_map = []
  130. for j in range(len(self.genmap)):
  131. new_line = []
  132. for i in range(len(self.genmap[j])):
  133. x, y = i, j
  134. n_count = self.countWalls(x, y)
  135. if self.genmap[y][x]:
  136. # It's a wall.
  137. if n_count < d_lmt:
  138. # It has too few wall neighbors, so kill it.
  139. new_line.append(False)
  140. else:
  141. # It has enough wall neighbors, so keep it.
  142. new_line.append(True)
  143. else:
  144. # It's a path.
  145. if n_count > a_lmt:
  146. # It has too many wall neighbors, so it becomes a wall.
  147. new_line.append(True)
  148. else:
  149. # It's not too crowded, so it stays a path.
  150. new_line.append(False)
  151. new_map.append(new_line)
  152. self.genmap = new_map
  153. def countWalls(self, x, y):
  154. count = 0
  155. for j in range(-1,2):
  156. for i in range(-1,2):
  157. n_x, n_y = x+i, y+j
  158. if i == 0 and j == 0:
  159. continue
  160. if n_x < 0 or n_x >= len(self.genmap[j]) or n_y == 0 or n_y >= len(self.genmap):
  161. # The target cell is at the edge of the map and this neighbor is off the edge.
  162. # So we make this neighbor count as a wall.
  163. count += 1
  164. #pass
  165. elif self.genmap[n_y][n_x]:
  166. # This neighbor is on the map and is a wall.
  167. count += 1
  168. return count
  169. def printScreen(self):
  170. wall = "II"
  171. path = " "
  172. for line in self.genmap:
  173. print("".join([wall if x else path for x in line]))
  174. print()
  175. def createImage(self):
  176. x, y = len(self.genmap[0]), len(self.genmap)
  177. if self.chunky:
  178. true_x, true_y = x*2, y*2
  179. else:
  180. true_x, true_y = x, y
  181. img = Image.new("RGB",(true_x,true_y),(0,0,0))
  182. lst = []
  183. # Walls are black by default
  184. c_wall = [random.randint(0,255), random.randint(0,255), random.randint(0,255)] if self.color else [0,0,0]
  185. # Paths are white by default
  186. c_space = [255-x for x in c_wall]
  187. if self.chunky:
  188. for line in self.genmap:
  189. for _ in range(2):
  190. for val in line:
  191. for _ in range(2):
  192. lst.append(tuple(c_wall) if val else tuple(c_space))
  193. else:
  194. for line in self.genmap:
  195. for val in line:
  196. lst.append(tuple(c_wall) if val else tuple(c_space))
  197. img.putdata(lst)
  198. if not os.path.exists("maps"):
  199. os.makedirs("maps")
  200. fn = self.id
  201. i = 0
  202. while os.path.exists("maps/{}.png".format(fn)):
  203. i += 1
  204. fn = self.id + "-" + str(i)
  205. img.save('maps/{}.png'.format(fn))
  206. print("Saved maps/{}.png".format(fn))
  207. def printArray(self):
  208. print("[",end="\n")
  209. for line in self.genmap:
  210. print("\t{},".format(line))
  211. print("]")
  212. def filename():
  213. hexes = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]
  214. fn = []
  215. for _ in range(16):
  216. fn.append(random.choice(hexes))
  217. return "".join(fn)
  218. def parseArgs(args):
  219. flags = {
  220. "--height" : 20,
  221. "--width" : 20,
  222. "--seed" : 45,
  223. "--death" : 4,
  224. "--birth" : 4,
  225. "--reps" : 2,
  226. "--out" : False,
  227. "--color" : False,
  228. "--chunky" : False,
  229. "--treas" : False,
  230. }
  231. for flag, default in flags.items():
  232. if flag in args:
  233. if flag == "--out":
  234. flags["--out"] = True
  235. elif flag == "--color":
  236. flags["--color"] = True
  237. elif flag == "--chunky":
  238. flags["--chunky"] = True
  239. else:
  240. flags[flag] = args[args.index(flag) + 1]
  241. return flags
  242. def main(args):
  243. flags = parseArgs(args)
  244. my_map = CellMap(flags["--height"],flags["--width"],flags["--seed"],flags["--death"],
  245. flags["--birth"],flags["--reps"],flags["--out"],flags["--color"],
  246. flags["--chunky"],flags["--treas"],)
  247. my_map.generateFullMap()
  248. if __name__ == "__main__":
  249. main(sys.argv)