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.6KB

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