Toggle Navigation
Hatchery
Eggs
May Contain Goblins
dungeonGenerator.py
Users
Badges
Login
Register
dungeonGenerator.py
raw
Content
#! /usr/bin/env python # coding: utf-8 # generator-1.py, a simple python dungeon generator by # James Spencer <jamessp [at] gmail.com>. # To the extent possible under law, the person who associated CC0 with # pathfinder.py has waived all copyright and related or neighboring rights # to pathfinder.py. # You should have received a copy of the CC0 legalcode along with this # work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. import random CHARACTER_TILES = {'stone': ' ', 'floor': '.', 'wall': '#'} class Generator(): def __init__(self, width=64, height=64, max_rooms=15, min_room_xy=5, max_room_xy=10, rooms_overlap=False, random_connections=1, random_spurs=3, tiles=CHARACTER_TILES): self.width = width self.height = height self.max_rooms = max_rooms self.min_room_xy = min_room_xy self.max_room_xy = max_room_xy self.rooms_overlap = rooms_overlap self.random_connections = random_connections self.random_spurs = random_spurs self.tiles = CHARACTER_TILES self.level = [] self.room_list = [] self.corridor_list = [] self.tiles_level = [] def gen_room(self): x, y, w, h = 0, 0, 0, 0 w = random.randint(self.min_room_xy, self.max_room_xy) h = random.randint(self.min_room_xy, self.max_room_xy) x = random.randint(1, (self.width - w - 1)) y = random.randint(1, (self.height - h - 1)) return [x, y, w, h] def random_room(self): max = len(self.room_list) - 1 return self.room_list[random.randint(0,random.randint(0,max))] def room_overlapping(self, room, room_list): x = room[0] y = room[1] w = room[2] h = room[3] for current_room in room_list: # The rectangles don't overlap if # one rectangle's minimum in some dimension # is greater than the other's maximum in # that dimension. if (x < (current_room[0] + current_room[2]) and current_room[0] < (x + w) and y < (current_room[1] + current_room[3]) and current_room[1] < (y + h)): return True return False def corridor_between_points(self, x1, y1, x2, y2, join_type='either'): if x1 == x2 and y1 == y2 or x1 == x2 or y1 == y2: return [(x1, y1), (x2, y2)] else: # 2 Corridors # NOTE: Never randomly choose a join that will go out of bounds # when the walls are added. join = None if join_type is 'either' and set([0, 1]).intersection( set([x1, x2, y1, y2])): join = 'bottom' elif join_type is 'either' and set([self.width - 1, self.width - 2]).intersection(set([x1, x2])) or set( [self.height - 1, self.height - 2]).intersection( set([y1, y2])): join = 'top' elif join_type is 'either': join = random.choice(['top', 'bottom']) else: join = join_type if join is 'top': return [(x1, y1), (x1, y2), (x2, y2)] elif join is 'bottom': return [(x1, y1), (x2, y1), (x2, y2)] def join_rooms(self, room_1, room_2, join_type='either'): # sort by the value of x sorted_room = [room_1, room_2] sorted_room.sort(key=lambda x_y: x_y[0]) x1 = sorted_room[0][0] y1 = sorted_room[0][1] w1 = sorted_room[0][2] h1 = sorted_room[0][3] x1_2 = x1 + w1 - 1 y1_2 = y1 + h1 - 1 x2 = sorted_room[1][0] y2 = sorted_room[1][1] w2 = sorted_room[1][2] h2 = sorted_room[1][3] x2_2 = x2 + w2 - 1 y2_2 = y2 + h2 - 1 # overlapping on x if x1 < (x2 + w2) and x2 < (x1 + w1): jx1 = random.randint(x2, x1_2) jx2 = jx1 tmp_y = [y1, y2, y1_2, y2_2] tmp_y.sort() jy1 = tmp_y[1] + 1 jy2 = tmp_y[2] - 1 corridors = self.corridor_between_points(jx1, jy1, jx2, jy2) self.corridor_list.append(corridors) # overlapping on y elif y1 < (y2 + h2) and y2 < (y1 + h1): if y2 > y1: jy1 = random.randint(y2, y1_2) jy2 = jy1 else: jy1 = random.randint(y1, y2_2) jy2 = jy1 tmp_x = [x1, x2, x1_2, x2_2] tmp_x.sort() jx1 = tmp_x[1] + 1 jx2 = tmp_x[2] - 1 corridors = self.corridor_between_points(jx1, jy1, jx2, jy2) self.corridor_list.append(corridors) # no overlap else: join = None if join_type is 'either': join = random.choice(['top', 'bottom']) else: join = join_type if join is 'top': if y2 > y1: jx1 = x1_2 + 1 jy1 = random.randint(y1, y1_2) jx2 = random.randint(x2, x2_2) jy2 = y2 - 1 corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'bottom') self.corridor_list.append(corridors) else: jx1 = random.randint(x1, x1_2) jy1 = y1 - 1 jx2 = x2 - 1 jy2 = random.randint(y2, y2_2) corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'top') self.corridor_list.append(corridors) elif join is 'bottom': if y2 > y1: jx1 = random.randint(x1, x1_2) jy1 = y1_2 + 1 jx2 = x2 - 1 jy2 = random.randint(y2, y2_2) corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'top') self.corridor_list.append(corridors) else: jx1 = x1_2 + 1 jy1 = random.randint(y1, y1_2) jx2 = random.randint(x2, x2_2) jy2 = y2_2 + 1 corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'bottom') self.corridor_list.append(corridors) def gen_level(self): # build an empty dungeon, blank the room and corridor lists for i in range(self.height): self.level.append(['stone'] * self.width) self.room_list = [] self.corridor_list = [] max_iters = self.max_rooms * 5 for a in range(max_iters): tmp_room = self.gen_room() if self.rooms_overlap or not self.room_list: self.room_list.append(tmp_room) else: tmp_room = self.gen_room() tmp_room_list = self.room_list[:] if self.room_overlapping(tmp_room, tmp_room_list) is False: self.room_list.append(tmp_room) if len(self.room_list) >= self.max_rooms: break # connect the rooms for a in range(len(self.room_list) - 1): self.join_rooms(self.room_list[a], self.room_list[a + 1]) # do the random joins for a in range(self.random_connections): room_1 = self.room_list[random.randint(0, len(self.room_list) - 1)] room_2 = self.room_list[random.randint(0, len(self.room_list) - 1)] self.join_rooms(room_1, room_2) # do the spurs for a in range(self.random_spurs): room_1 = [random.randint(2, self.width - 2), random.randint( 2, self.height - 2), 1, 1] room_2 = self.room_list[random.randint(0, len(self.room_list) - 1)] self.join_rooms(room_1, room_2) # fill the map # paint rooms for room_num, room in enumerate(self.room_list): for b in range(room[2]): for c in range(room[3]): self.level[room[1] + c][room[0] + b] = 'floor' # paint corridors for corridor in self.corridor_list: x1, y1 = corridor[0] x2, y2 = corridor[1] for width in range(abs(x1 - x2) + 1): for height in range(abs(y1 - y2) + 1): self.level[min(y1, y2) + height][ min(x1, x2) + width] = 'floor' if len(corridor) == 3: x3, y3 = corridor[2] for width in range(abs(x2 - x3) + 1): for height in range(abs(y2 - y3) + 1): self.level[min(y2, y3) + height][ min(x2, x3) + width] = 'floor' # paint the walls for row in range(1, self.height - 1): for col in range(1, self.width - 1): if self.level[row][col] == 'floor': if self.level[row - 1][col - 1] == 'stone': self.level[row - 1][col - 1] = 'wall' if self.level[row - 1][col] == 'stone': self.level[row - 1][col] = 'wall' if self.level[row - 1][col + 1] == 'stone': self.level[row - 1][col + 1] = 'wall' if self.level[row][col - 1] == 'stone': self.level[row][col - 1] = 'wall' if self.level[row][col + 1] == 'stone': self.level[row][col + 1] = 'wall' if self.level[row + 1][col - 1] == 'stone': self.level[row + 1][col - 1] = 'wall' if self.level[row + 1][col] == 'stone': self.level[row + 1][col] = 'wall' if self.level[row + 1][col + 1] == 'stone': self.level[row + 1][col + 1] = 'wall' def gen_tiles_level(self): for row_num, row in enumerate(self.level): tmp_tiles = [] for col_num, col in enumerate(row): if col == 'stone': tmp_tiles.append(self.tiles['stone']) if col == 'floor': tmp_tiles.append(self.tiles['floor']) if col == 'wall': tmp_tiles.append(self.tiles['wall']) self.tiles_level.append(''.join(tmp_tiles)) print('Room List: ', self.room_list) print('\nCorridor List: ', self.corridor_list) [print(row) for row in self.tiles_level]