import json
import os
-i = random.randint(0,100)
-
-
ATTRIBUTE_MAP = {
- '#': {'base': 'cwall',
- 'behaviour': [],
- },
- ' ': {'base': 'floor',
- 'behaviour': ['walk', 'fly'],
- '#': {'floor': {'base': 'cwall',
- 'behaviour': [],
- },
-- },
+ ' ': {'floor': {'base': 'floor',
- 'behaviour': ['walk', 'fly'],
- },
- },
++ 'behaviour': ['walk', 'fly'],
++ },
++ },
+ 'o': {'tunnels': {'base': 'underground',
+ 'behaviour': [],
- }
- },
++ }
++ },
+ '-': {'tunnels': {'base': 'tunnel',
- 'behaviour': ['walk',],
- },
- },
++ 'behaviour': ['walk', ],
++ },
++ },
}
- def link_passage(self, local_tile, foriegn_tile):
+class Room:
+ def __init__(self, coordinates, region):
+ """
+ """
+ self.coordinates = [coordinates]
+ self.region = region
+ self.max_connections = 1
+ self.passages = []
+ self.tunnels = []
+
+ def is_linked(self):
+ """
+ Check if the room is linked to another room
+ :return: Whether the room has any links or not
+ """
+ return len(self.passages) + len(self.tunnels) > 0
+
+ def add_region(self, coordinates):
+ """
+ Add a new region into an existing room
+ :param coordinates: region coordinates to be added to room
+ :return:
+ """
+ self.coordinates.append(coordinates)
+
+ def connect_rooms(self, other_rooms):
+ """ Find the nearest rooms to this room
+ :param other_rooms: list of Rooms objects that we are searching
+ :return:
+ """
+ distance = []
+ other_tile = []
+ this_tile = []
+ target_rooms = []
+ for coord in self.coordinates:
+ for room in other_rooms:
+ if self == room:
+ continue
+ for new_coord in room.coordinates:
+ distance.append(
+ math.sqrt((coord[0] - new_coord[0]) ** 2 +
+ (coord[1] - new_coord[1]) ** 2))
+ other_tile.append(new_coord)
+ this_tile.append(coord)
+ target_rooms.append(room)
+
+ sorted_indices = [i[0] for i in sorted(enumerate(distance),
+ key=lambda x:x[0])]
+ for index in sorted_indices:
+ if len(self.passages) + len(self.tunnels) >= self.max_connections:
+ break
+ if not target_rooms[index].is_linked():
+ self.link_passage(this_tile[index], other_tile[index])
+ target_rooms[index].link_passage(
+ other_tile[index], this_tile[index])
+
- :param foriegn_tile: tile in another room to which we wish to link
++ def link_passage(self, local_tile, foreign_tile):
+ """ Link a passage between two rooms
+ :param local_tile: tile in this room to which we wish to link
- self.passages.append([local_tile, foriegn_tile])
++ :param foreign_tile: tile in another room to which we wish to link
+ :return:
+ """
- print(region)
- print(self.region)
++ self.passages.append([local_tile, foreign_tile])
+
+ def render_region(self, region, room_dist, region_size, tile_map, x, y):
+ """ Check if a region is in this room and return the required tiles
+ :param region: Region that we wish to render
+ :param room_dist: Tile separation distance from other rooms
+ :param region_size: Region size in tiles
++ :param tile_map: Tile map to update
++ :param x: X coordinate
++ :param y: Y coordinate
+ :return:
+ """
+ if region in self.coordinates:
+ print(self.coordinates)
+ for ht in range(room_dist, region_size - room_dist):
+ for wt in range(room_dist, region_size - room_dist):
+ tile_map[x + ht][y + wt] = ' '
+
+ # if w == 0:
+ # w_dist = self.dist_from_other_rooms
+ # elif self.region_map[h][w-1] == region_selected:
+ # w_dist = 0
+ # else:
+ # w_dist = self.dist_from_other_rooms
+ #
+ # if w + 1 == self.width:
+ # e_dist = self.region_size - self.dist_from_other_rooms
+ # elif self.region_map[h][w+1] == region_selected:
+ # e_dist = self.region_size
+ # else:
+ # e_dist = self.region_size - self.dist_from_other_rooms
+ #
+ # if h == 0:
+ # n_dist = self.dist_from_other_rooms
+ # elif self.region_map[h-1][w] == region_selected:
+ # n_dist = 0
+ # else:
+ # n_dist = self.dist_from_other_rooms
+ #
+ # if h + 1 == self.height:
+ # s_dist = self.region_size - self.dist_from_other_rooms
+ # elif self.region_map[h+1][w] == region_selected:
+ # s_dist = self.region_size
+ # else:
+ # s_dist = self.region_size - self.dist_from_other_rooms
+ #
+ # for wt in range(w_dist, e_dist):
+ # for ht in range(n_dist, s_dist):
+ # self.map[h * self.region_size + ht]\
+ # [w * self.region_size + wt] = ' '
+
+ def random_cardinal():
+ """Return a random cardinal direction for random walks."""
+ return random.choice([(0, 1), (0, -1), (1, 0), (-1, 0)])
+
class LevelGenerator:
width = 0
height = 0
- rooms = 0
+ no_rooms = 0
+ rooms = []
map = None
- min_room_size = 0
- max_room_size = 0
- dist_from_edge = 0
+ map2 = None
dist_from_other_rooms = 0
- regions = None
- region = 0
- region_size_in_tiles = 0
+ region_map = None
+ regions = 0
+ region_size = 0
- def __init__(self, width, height, rooms, min_room_size, max_room_size, dist_from_edge,
- dist_from_other_rooms, region_size_in_tiles):
+ def __init__(self, width, height, no_rooms, dist_from_other_rooms,
+ region_size):
""" Initialize the level parameters
"""
self.width = width
self.height = height
- self.rooms = rooms
- self.min_room_size = min_room_size
- self.max_room_size = max_room_size
- self.dist_from_edge = dist_from_edge
+ self.no_rooms = no_rooms
self.dist_from_other_rooms = dist_from_other_rooms
- self.region_size_in_tiles = region_size_in_tiles
+ self.region_size = region_size
+ self.region_coordinates = []
def generate(self):
""" Generate a random level map
"""
- self.generate_regions()
- row = ['#' for x in range(self.width * self.region_size_in_tiles)]
- self.map = [row[:] for x in range(self.height * self.region_size_in_tiles)]
- regions_selected = random.sample(range(self.region), min(self.region, self.rooms))
+ self.generate_rooms()
+ regions_selected = random.sample(range(self.regions),
+ min(self.regions, self.no_rooms))
+ row = ['#' for x in range(self.width * self.region_size)]
+ self.map = [row[:] for x in range(self.height * self.region_size)]
+ self.map2 = [row[:] for x in range(self.height * self.region_size)]
print('Regions: %s' % str(regions_selected))
for region in regions_selected:
- self.generate_tiles(region)
+ self.rooms[region].connect_rooms(
+ [self.rooms[i] for i in regions_selected])
- self.generate_underlayer()
+ self.generate_room(region)
- # self.rooms[coord[0]].render_region(
- # coord[1], self.dist_from_other_rooms, self.region_size,
- # self.map2, coord[1][0] * self.region_size,
- # coord[1][1] * self.region_size)
+ region_coordinates_selected = [p for p in self.region_coordinates if
+ p[0] in regions_selected]
+ print('Coords: %s' % str(region_coordinates_selected))
+ for coord in region_coordinates_selected:
+ print(str(coord))
++ self.rooms[coord[0]].render_region(
++ coord[1], self.dist_from_other_rooms, self.region_size,
++ self.map2, coord[1][0] * self.region_size,
++ coord[1][1] * self.region_size)
++ # self.generate_underlayer()
- def generate_regions(self):
+ def generate_rooms(self):
""" Generate a random level region map
"""
- row = ['#' for x in range(self.width)]
- self.regions = [row[:] for x in range(self.height)]
+ row = [0 for x in range(self.width)]
+ self.region_map = [row[:] for x in range(self.height)]
for h in range(self.height):
for w in range(self.width):
random_number = random.randint(0, 2)
+ increment_region = False
if w == h == 0:
- self.regions[h][w] = self.region
- self.region += 1
+ update_value = self.regions
+ increment_region = True
elif h == 0:
if random_number > 1:
- try:
- self.regions[h][w] = self.regions[h][w - 1]
- except:
- print(h, w)
- raise
+ update_value = self.region_map[h][w - 1]
else:
- self.regions[h][w] = self.region
- self.region += 1
+ update_value = self.regions
+ increment_region = True
elif w == 0:
if random_number > 1:
- self.regions[h][w] = self.regions[h - 1][w]
+ update_value = self.region_map[h - 1][w]
else:
- self.regions[h][w] = self.region
- self.region += 1
+ update_value = self.regions
+ increment_region = True
else:
if random_number > 1:
- self.regions[h][w] = self.regions[h - 1][w]
+ update_value = self.region_map[h - 1][w]
elif random_number > 0:
- self.regions[h][w] = self.regions[h][w - 1]
+ update_value = self.region_map[h][w - 1]
else:
- self.regions[h][w] = self.region
- self.region += 1
+ update_value = self.regions
+ increment_region = True
+ self.region_map[h][w] = update_value
+ if increment_region:
- r = Room([h, w], self.regions)
++ r = Room([h, w], update_value)
+ self.rooms.append(r)
+ self.region_coordinates.append([update_value, [h, w]])
+ self.regions += 1
+ else:
- self.rooms[-1].add_region([h, w])
++ for r in self.rooms:
++ if r.region == update_value:
++ r.add_region([h, w])
+ self.region_coordinates.append([update_value, [h, w]])
+ def generate_underlayer(self):
+ """Generate a small mess of tunnels to have something."""
+ width = len(self.map[0])
+ height = len(self.map)
+ row = ['o' for x in range(width)]
+ self.underlayer = [row[:] for x in range(height)]
+ # we create a set of biased random walks to create the tunnel network
+ for walk in range(random.randint(3, 6)):
+ x = width // 2 + random.randint(-8, 8)
+ y = height // 2 + random.randint(-8, 8)
+ dir_x, dir_y = random_cardinal()
+ max_steps = random.randint(40, width * height // 4)
+ for step in range(20, max_steps):
+ if 0 < x < width - 1:
+ if 0 < y < height - 1:
+ self.underlayer[y][x] = '-'
+ if random.random() > 0.7:
+ dir_x, dir_y = random_cardinal()
+ x += dir_x
+ y += dir_y
+
+ def generate_tiles(self, region_selected):
++ """Generate a small mess of tunnels to have something."""
++ width = len(self.map[0])
++ height = len(self.map)
++ row = ['o' for x in range(width)]
++ self.underlayer = [row[:] for x in range(height)]
++ # we create a set of biased random walks to create the tunnel network
++ for walk in range(random.randint(3, 6)):
++ x = width // 2 + random.randint(-8, 8)
++ y = height // 2 + random.randint(-8, 8)
++ dir_x, dir_y = random_cardinal()
++ max_steps = random.randint(40, width * height // 4)
++ for step in range(20, max_steps):
++ if 0 < x < width - 1:
++ if 0 < y < height - 1:
++ self.underlayer[y][x] = '-'
++ if random.random() > 0.7:
++ dir_x, dir_y = random_cardinal()
++ x += dir_x
++ y += dir_y
++
+ def generate_room(self, region_selected):
"""
+ :param region_selected:
+ :return:
"""
for h in range(self.height):
for w in range(self.width):
- if self.regions[h][w] == region_selected:
+ if self.region_map[h][w] == region_selected:
if w == 0:
w_dist = self.dist_from_other_rooms
- elif self.regions[h][w-1] == region_selected:
+ elif self.region_map[h][w-1] == region_selected:
w_dist = 0
else:
w_dist = self.dist_from_other_rooms
if w + 1 == self.width:
- e_dist = self.region_size_in_tiles - self.dist_from_other_rooms
- elif self.regions[h][w+1] == region_selected:
- e_dist = self.region_size_in_tiles
+ e_dist = self.region_size - self.dist_from_other_rooms
+ elif self.region_map[h][w+1] == region_selected:
+ e_dist = self.region_size
else:
- e_dist = self.region_size_in_tiles - self.dist_from_other_rooms
+ e_dist = self.region_size - self.dist_from_other_rooms
if h == 0:
n_dist = self.dist_from_other_rooms
- elif self.regions[h-1][w] == region_selected:
+ elif self.region_map[h-1][w] == region_selected:
n_dist = 0
else:
n_dist = self.dist_from_other_rooms
if h + 1 == self.height:
- s_dist = self.region_size_in_tiles - self.dist_from_other_rooms
- elif self.regions[h+1][w] == region_selected:
- s_dist = self.region_size_in_tiles
+ s_dist = self.region_size - self.dist_from_other_rooms
+ elif self.region_map[h+1][w] == region_selected:
+ s_dist = self.region_size
else:
- s_dist = self.region_size_in_tiles - self.dist_from_other_rooms
+ s_dist = self.region_size - self.dist_from_other_rooms
for wt in range(w_dist, e_dist):
for ht in range(n_dist, s_dist):
- self.map[h * self.region_size_in_tiles + ht][w * self.region_size_in_tiles + wt] = ' '
+ self.map[h * self.region_size + ht]\
+ [w * self.region_size + wt] = str(region_selected)
def display(self):
file = open('map.txt', 'w')
+ print('-----------------')
for l in self.map:
print(''.join(l))
file.write(''.join(l))
file.write('\n')
- print('')
- for l in self.underlayer:
+ print('-----------------')
+ for l in self.map2:
print(''.join(l))
file.write(''.join(l))
file.write('\n')
+ print('-----------------')
++ try:
++ for l in self.underlayer:
++ print(''.join(l))
++ file.write(''.join(l))
++ file.write('\n')
++ except AttributeError:
++ pass
file.close()
- self._to_json()
- for l in self.regions:
+ for l in self.region_map:
+ # self._to_json()
print(l)
def _to_json(self):
level = {}
+ level['tileset'] = 'bunker'
level['tiles'] = []
- for l in self.map:
+ for l, lu in zip(self.map, self.underlayer):
row = []
- for t in l:
- row.append(ATTRIBUTE_MAP[t])
+ for t1, t2 in zip(l, lu):
+ tile = ATTRIBUTE_MAP[t1].copy()
+ tile.update(ATTRIBUTE_MAP[t2])
+ row.append(tile)
level['tiles'].append(row)
- name = os.path.join(os.path.dirname(__file__), '..', 'levels', 'map.json')
- # FIXME: Do a lot better here
+ # FIXME: Do a lot better here
# Crude hack so the level is written into the levels folder
+ name = os.path.join(os.path.dirname(__file__), '..', 'levels', 'map.json')
f = open(name, 'w')
json.dump(level, f)
f.close()
if __name__ == '__main__':
while True:
- level = LevelGenerator(width=8, height=5, rooms=12, min_room_size=5, max_room_size=20,
- dist_from_edge=2, dist_from_other_rooms=1, region_size_in_tiles=6)
+ level = LevelGenerator(width=4, height=3, no_rooms=4,
+ dist_from_other_rooms=0, region_size=3)
level.generate()
level.display()
input("Press Enter to continue...")