Compare commits

...

4 Commits

Author SHA1 Message Date
Charles Peyrat ebca28930c Remove debug output. Oops. 2021-01-21 03:28:46 +01:00
Charles Peyrat bcfde6fa49 Move code around so loops placement isn't stopped by walls 2021-01-21 03:27:31 +01:00
Charles Peyrat 5981927dac Optimization for the loop placing algorithm 2021-01-21 03:26:54 +01:00
Charles Peyrat 38878687c4 Add new room type : rectangular rooms 2021-01-16 00:35:41 +01:00
1 changed files with 55 additions and 14 deletions

View File

@ -21,36 +21,38 @@ DEFAULT_PARAMS = {
"large_circular_room": .10, "large_circular_room": .10,
"circular_holes": .5, "circular_holes": .5,
"loop_tries": 40, "loop_tries": 40,
"loop_max": 5, "loop_max": 8,
"loop_threshold": 15, "loop_threshold": 15,
"spawn_per_region": [1, 2], "spawn_per_region": [1, 2],
"room_chances" : { "room_chances" : {
"circular" : 5, "circular" : 1,
"chunks" : 1, "chunks" : 1,
"rectangle" : 1,
}, },
} }
def dist(level, y1, x1, y2, x2): def test_dist(level, y1, x1, y2, x2, threshold):
""" """
Compute the minimum walking distance between points (y1, x1) and (y2, x2) on a Tile grid Returns whether the minimum walking distance between points (y1, x1) and
(y2, x2) on the Tile grid level is greater than threshold
""" """
# simple breadth first search # simple breadth first search
copy = [[t for t in row] for row in level] copy = [[t for t in row] for row in level]
dist = -1 dist = -1
queue, next_queue = [[y1, x1]], [0] queue, next_queue = [[y1, x1]], [0]
while next_queue: while next_queue and dist < threshold:
next_queue = [] next_queue = []
dist += 1 dist += 1
while queue: while queue:
y, x = queue.pop() y, x = queue.pop()
copy[y][x] = Tile.EMPTY copy[y][x] = Tile.EMPTY
if y == y2 and x == x2: if y == y2 and x == x2:
return dist return False
for y, x in Map.neighbourhood(copy, y, x): for y, x in Map.neighbourhood(copy, y, x):
if copy[y][x].can_walk(): if copy[y][x].can_walk():
next_queue.append([y, x]) next_queue.append([y, x])
queue = next_queue queue = next_queue
return -1 return True
class Generator: class Generator:
@ -147,7 +149,7 @@ class Generator:
return True return True
# if adding the path would make the two tiles significantly closer # if adding the path would make the two tiles significantly closer
# and its sides don't touch already placed terrain, build it # and its sides don't touch already placed terrain, build it
if dist(level, y1, x1, y2, x2) < 20 and verify_sides(): if test_dist(level, y1, x1, y2, x2, 20) and verify_sides():
y, x = y1 + dy, x1 + dx y, x = y1 + dy, x1 + dx
while level[y][x] == Tile.EMPTY: while level[y][x] == Tile.EMPTY:
level[y][x] = Tile.FLOOR level[y][x] = Tile.FLOOR
@ -216,7 +218,8 @@ class Generator:
return False return False
# see if the path ahead is clear. needed in the case of non convex room # see if the path ahead is clear. needed in the case of non convex room
for i in range(length + 1): for i in range(length + 1):
if room[y + i * dy][x + i * dx] != Tile.EMPTY: if not(0 <= y + i * dy < rh and 0 <= x + i * dx < rw) \
or room[y + i * dy][x + i * dx] != Tile.EMPTY:
return False return False
for i in range(length): for i in range(length):
room[y + i * dy][x + i * dx] = Tile.FLOOR room[y + i * dy][x + i * dx] = Tile.FLOOR
@ -252,17 +255,15 @@ class Generator:
if room[y][x] == Tile.EMPTY and \ if room[y][x] == Tile.EMPTY and \
Generator.build_door(room, y, x, dy, dx, length): Generator.build_door(room, y, x, dy, dx, length):
break break
else:
return None, None
return y + length * dy, x + length * dx, dy, dx return y + length * dy, x + length * dx, dy, dx
def create_chunk_room(self, spawnable: bool = True) \ def create_chunk_room(self, spawnable: bool = True) \
-> Tuple[List[List[Tile]], int, int, int, int]: -> Tuple[List[List[Tile]], int, int, int, int]:
""" """
Create and return as a tile grid a room that is composed of multiple create and return as a tile grid a room that is composed of multiple
overlapping circles of the same radius overlapping circles of the same radius
Also return door info so we know how to place the room in the level also return door info so we know how to place the room in the level
""" """
height, width = 15, 15 height, width = 15, 15
nb_chunks, r = 6, 3 nb_chunks, r = 6, 3
@ -341,6 +342,42 @@ class Generator:
return room, door_y, door_x, dy, dx return room, door_y, door_x, dy, dx
def create_rectangle_room(self, spawnable: bool = True) \
-> Tuple[List[List[Tile]], int, int, int, int]:
"""
create and return as a tile grid a rectangular room
also return door info so we know how to place the room in the level
"""
shrt, lng = randint(3, 6), randint(6, 12)
if random() < .5:
height, width = shrt, lng
else:
height, width = lng, shrt
room = []
h_sup, w_sup, h_off, w_off = self.corr_meta_info()
min_w, max_w = w_off + 1, width + w_off
min_h, max_h = h_off + 1, height + h_off
for i in range(height + h_sup + 2):
room.append([])
for j in range(width + w_sup + 2):
if min_h <= i <= max_h and min_w <= j <= max_w:
room[-1].append(Tile.FLOOR)
else:
room[-1].append(Tile.EMPTY)
# log all placed tiles as spawn positions
if spawnable:
self.register_spawn_area(room)
# attach exit
door_y, door_x, dy, dx = self.attach_door(room, h_sup, w_sup,
h_off, w_off)
return room, door_y, door_x, dy, dx
def create_random_room(self, spawnable: bool = True) \ def create_random_room(self, spawnable: bool = True) \
-> Tuple[List[list], int, int, int, int]: -> Tuple[List[list], int, int, int, int]:
""" """
@ -361,6 +398,8 @@ class Generator:
return self.create_circular_room(spawnable = spawnable) return self.create_circular_room(spawnable = spawnable)
elif key == "chunks": elif key == "chunks":
return self.create_chunk_room(spawnable = spawnable) return self.create_chunk_room(spawnable = spawnable)
elif key == "rectangle":
return self.create_rectangle_room(spawnable = spawnable)
def register_spawn_area(self, area: List[List[Tile]]) -> None: def register_spawn_area(self, area: List[List[Tile]]) -> None:
""" """
@ -450,7 +489,6 @@ class Generator:
tries += 1 tries += 1
# post-processing # post-processing
self.place_walls(level)
# because when a room is placed, it leads to exactly one previously # because when a room is placed, it leads to exactly one previously
# placed room, the level has a tree like structure with the starting # placed room, the level has a tree like structure with the starting
@ -464,6 +502,9 @@ class Generator:
y, x = randint(0, height - 1), randint(0, width - 1) y, x = randint(0, height - 1), randint(0, width - 1)
loops += self.add_loop(level, y, x) loops += self.add_loop(level, y, x)
# surround the floor with walls
self.place_walls(level)
# place an exit ladder # place an exit ladder
y, x = randint(0, height - 1), randint(0, width - 1) y, x = randint(0, height - 1), randint(0, width - 1)
while level[y][x] != Tile.FLOOR or \ while level[y][x] != Tile.FLOOR or \