Created
February 2, 2012 08:52
-
-
Save laserbat/1722426 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def createCaveLevel(self, w, h): | |
""" | |
Simple CA cave generator, sometimes generates not-so-cavelike | |
levels :( | |
Uses algorithm from: | |
roguebasin.roguelikedevelopment.org/index.php?title= | |
Cellular_Automata_Method_for_Generating_Random_Cave-Like_Levels | |
""" | |
cave = [] # Level | |
cave2 = [] # Used for CA | |
for x in range(0, w + 1): # Create empty level | |
cave.append([]) | |
cave2.append([WALL] * (h + 1)) # Fill cave2 with walls | |
for y in range(0, h + 1): | |
# And cave with random cells | |
if libtcod.random_get_int(self.rand, 0, CA_FILL_MAXRAND) \ | |
<= CA_FILL_PROB: | |
cave[x].append(WALL) | |
else: | |
cave[x].append(FLOOR) | |
for iterations in range(len(CA_ITERATIONS)): # The CA itself | |
cutoff = CA_CUTOFF[iterations] | |
for m in range(CA_ITERATIONS[iterations]): | |
for x in range(2, w - 1): | |
for y in range(2, h - 1): | |
c = c2 = 0 | |
for x2 in range(-1, 2): # All adjacent cells | |
for y2 in range(-1, 2): | |
if cave[x + x2][y + y2] != FLOOR: | |
c += 1 | |
for x2 in range(x - 2, x + 3): # And cells that only | |
for y2 in range(y - 2, y + 3): # two tiles far. | |
if abs(x2 - x) == 2 and abs(y - y2) == 2: | |
continue | |
if x2 < 0 or y2 < 0 or x2 >= w or y2 >= h: | |
continue | |
if cave[x2][y2] != FLOOR: | |
c2 += 1 | |
if c >= cutoff[0] or c2 <= cutoff[1]: | |
cave2[x][y] = WALL | |
else: | |
cave2[x][y] = FLOOR | |
for x in range(0, w + 1): | |
for y in range(0, h + 1): | |
cave[x][y] = cave2[x][y] | |
x = y = 0 # Find a seed for floodfill | |
i = 0 | |
while not cave[x][y]: | |
x = libtcod.random_get_int(self.rand, 0, w) | |
y = libtcod.random_get_int(self.rand, 0, h) | |
i += 1 | |
if i > MAX_CELLS: | |
raise NoFloorCellException | |
cave = self.rFloodFill(cave) # Floodfill it | |
if cave == False: | |
return self.createCaveLevel(w, h) | |
# Create cells in self.matrix | |
for x in range(0, w + 1): | |
self.matrix.append([]) | |
for y in range(0, h + 1): | |
if self.levelRange((x, y)): | |
self.matrix[x].append(Cell( # Create cell | |
cave[x][y], | |
cave[x][y], | |
(x, y), | |
self.noise, self | |
) | |
) | |
self.update((x,y)) | |
else: # Create permanent wall | |
self.matrix[x].append(PermaWall((x, y), self.noise, self)) | |
self.update((x,y)) | |
x = y = 0 # Create a test monster | |
i = 0 | |
while not self[x][y].isWalkable(): | |
x = libtcod.random_get_int(self.rand, 0, w) | |
y = libtcod.random_get_int(self.rand, 0, h) | |
i += 1 | |
if i > MAX_CELLS: | |
raise NoFloorCellException | |
# Test monster | |
self[x][y].mob = Mob((x,y),(self.noise,self.noise1d),self) | |
# And find free cell for player | |
self.px = self.py = 0 | |
i = 0 | |
while not self[self.px][self.py].isWalkable(): | |
self.px = libtcod.random_get_int(self.rand, 0, w) | |
self.py = libtcod.random_get_int(self.rand, 0, h) | |
i += 1 | |
if i > MAX_CELLS: | |
raise NoFloorCellException | |
# This code is useful for debugging level generator | |
""" | |
for y in range(0, h + 1): | |
for x in range(0, w + 1): | |
if self[x][y].isTransparent(): | |
sys.stdout.write(".") | |
else: | |
sys.stdout.write("#") | |
""" | |
def rFloodFill(self,fmap): | |
""" Split level into regions | |
uses floodfill function """ | |
sys.setrecursionlimit(REC_LIMIT) # It sometimes hits default | |
# recursion limit | |
# Mark every floor tile in every disconnected area | |
i = 2 | |
for x in range(len(fmap)): | |
for y in range(len(fmap[0])): | |
if fmap[x][y] == FLOOR: # FLOOR = 1 | |
# So, it wouldn't floodfill already marked areas | |
fmap = self.floodFill((x,y), (1,i), fmap) # Save result | |
# of floodfill | |
i += 1 # And increase number of disconected areas | |
areas = [0] * (i - 2) # Set every area size to 0 | |
for x in range(len(fmap)): | |
for y in range(len(fmap[0])): | |
if fmap[x][y]: | |
areas[fmap[x][y] - 2] += 1 # And add one to it's size | |
# for every cell marked with this number. | |
l = 0 # Largest area | |
for u in range(len(areas)): | |
if areas[u] > areas[l]: | |
l = u | |
# print l, areas | |
fmap2 = [] # New map | |
if areas[l] <= (len(fmap) * len(fmap[0])) / 3: | |
return False | |
l += 2 | |
for x in range(len(fmap)): | |
fmap2.append([]) | |
for y in range(len(fmap[0])): | |
if fmap[x][y] == l: | |
fmap2[x].append(FLOOR) | |
else: | |
fmap2[x].append(WALL) | |
""" | |
for x in range(len(fmap2[0])): | |
for y in range(len(fmap2)): | |
sys.stdout.write(str(fmap[y][x])) | |
""" | |
sys.setrecursionlimit(REC_LIMIT_DEFAULT) | |
return fmap2 | |
def floodFill(self, coords, colors, fmap): | |
""" | |
Recursive floodfill function. | |
""" | |
(x, y) = coords # Seed | |
(old, new) = colors | |
if fmap[x][y] != old: | |
return | |
fmap[x][y] = new | |
for x2 in range(-1,2): # Recursive calls | |
for y2 in range(-1,2): | |
self.floodFill((x + x2, y + y2), colors, fmap) | |
return fmap # Return result of floodfill |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment