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,
"circular_holes": .5,
"loop_tries": 40,
"loop_max": 5,
"loop_max": 8,
"loop_threshold": 15,
"spawn_per_region": [1, 2],
"room_chances" : {
"circular" : 5,
"circular" : 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
copy = [[t for t in row] for row in level]
dist = -1
queue, next_queue = [[y1, x1]], [0]
while next_queue:
while next_queue and dist < threshold:
next_queue = []
dist += 1
while queue:
y, x = queue.pop()
copy[y][x] = Tile.EMPTY
if y == y2 and x == x2:
return dist
return False
for y, x in Map.neighbourhood(copy, y, x):
if copy[y][x].can_walk():
next_queue.append([y, x])
queue = next_queue
return -1
return True
class Generator:
@ -147,7 +149,7 @@ class Generator:
return True
# if adding the path would make the two tiles significantly closer
# 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
while level[y][x] == Tile.EMPTY:
level[y][x] = Tile.FLOOR
@ -216,7 +218,8 @@ class Generator:
return False
# see if the path ahead is clear. needed in the case of non convex room
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
for i in range(length):
room[y + i * dy][x + i * dx] = Tile.FLOOR
@ -252,17 +255,15 @@ class Generator:
if room[y][x] == Tile.EMPTY and \
Generator.build_door(room, y, x, dy, dx, length):
break
else:
return None, None
return y + length * dy, x + length * dx, dy, dx
def create_chunk_room(self, spawnable: bool = True) \
-> 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
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
nb_chunks, r = 6, 3
@ -341,6 +342,42 @@ class Generator:
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) \
-> Tuple[List[list], int, int, int, int]:
"""
@ -361,6 +398,8 @@ class Generator:
return self.create_circular_room(spawnable = spawnable)
elif key == "chunks":
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:
"""
@ -450,7 +489,6 @@ class Generator:
tries += 1
# post-processing
self.place_walls(level)
# because when a room is placed, it leads to exactly one previously
# 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)
loops += self.add_loop(level, y, x)
# surround the floor with walls
self.place_walls(level)
# place an exit ladder
y, x = randint(0, height - 1), randint(0, width - 1)
while level[y][x] != Tile.FLOOR or \