def calc_z_splits(self, offset): """ Calculate horizontal splitting lines for the segment of surface map specified by offset (vertical offset) - Uses a depth first algorithm to create splitting lines. :params offset: vertical offset within the surface map. This is defined by the x_split :returns: a list of z values to specify the horizontal splitting lines for the current vertical offset within the surface map. """ partition_lines = [] segments = [] if self.z_length / 2 > self.MIN_YARD_SIZE[1]: segments.append((self.z_length, 0)) while len(segments) > 0: top, bottom = segments.pop() # NOTE: z_start+bottom and z_end+top are used as seeds to ensure different divisors rand_div = float( rand_range(self.z_start + bottom + offset, self.z_end + top + offset, 230, 170)) / 100 curr = bottom + (int(round(float(top - bottom) / rand_div))) partition_lines.append(curr) if (top - curr + 1) / 2 > self.MIN_YARD_SIZE[1]: segments.append((top, curr + 1)) if (curr - bottom) / 2 > self.MIN_YARD_SIZE[1]: segments.append((curr, bottom)) partition_lines.append(self.z_length) partition_lines.sort() return partition_lines
def calc_x_splits(self): """ Calculate vertical splitting lines for the surface map - Uses a depth first algorithm to create splitting lines. :returns: a list of x values to specify the vertical splitting line. """ partition_lines = [] segments = [] if self.x_length / 2 > self.MIN_YARD_SIZE[0]: segments.append((self.x_length, 0)) while len(segments) > 0: top, bottom = segments.pop() # NOTE: x_start+bottom and x_end+top are used as seeds to ensure different divisors rand_div = float( rand_range(self.x_start + bottom, self.x_end + top, 230, 170)) / 100 curr = bottom + (int(round(float(top - bottom) / rand_div))) partition_lines.append(curr) if (top - curr + 1) / 2 > self.MIN_YARD_SIZE[0]: segments.append((top, curr + 1)) if (curr - bottom) / 2 > self.MIN_YARD_SIZE[0]: segments.append((curr, bottom)) partition_lines.append(self.x_length) partition_lines.sort() return partition_lines
def generate_building_door_blocks(self, new_surface, partition): """ Generate a single door block on the edge of the building lot :params new_surface: a post CA Surface object to be modified and returned :params x_start, x_end, z_start, z_end: the current partition bounds :returns: a modified new_surface that has the building door cells set (also fills the self.building_doors list with coords to the door block) """ x_start, x_end, z_start, z_end = self.get_partition_bounds(partition) option = rand_range(x_start, z_start, 3, 0) # pick one of four options for door placement curr = (x_end - ((x_end - x_start) / 2), (z_end - ((z_end - z_start) / 2)) ) # set curr to center of yard if new_surface.surface_map[curr[0]][curr[1]].type != Block.BUILDING: # if center block is not a building lot, return return new_surface # OPTION 1: look for yard edge to the left if option == 0: while self.within_bounds( new_surface, curr ) and new_surface.surface_map[curr[0]][curr[1]].type != Block.YARD: curr = (curr[0] + 1, curr[1]) curr = (curr[0] - 1, curr[1]) # OPTION 2: look for yard edge to the right elif option == 1: while self.within_bounds( new_surface, curr ) and new_surface.surface_map[curr[0]][curr[1]].type != Block.YARD: curr = (curr[0] - 1, curr[1]) curr = (curr[0] + 1, curr[1]) # OPTION 3: look for yard edge upward elif option == 2: while self.within_bounds( new_surface, curr ) and new_surface.surface_map[curr[0]][curr[1]].type != Block.YARD: curr = (curr[0], curr[1] + 1) curr = (curr[0], curr[1] - 1) # OPTION 4: look for yard edge to the downward elif option == 3: while self.within_bounds( new_surface, curr ) and new_surface.surface_map[curr[0]][curr[1]].type != Block.YARD: curr = (curr[0], curr[1] - 1) curr = (curr[0], curr[1] + 1) self.building_door_blocks.append(curr) new_surface.surface_map[curr[0]][curr[1]].type = Block.BUILDING_DOOR return new_surface
def generate_building_lots(self, new_surface, partition): """ Generate a single building lot within the yard within the given partition :params new_surface: a post CA Surface object to be modified and returned :params x_start, x_end, z_start, z_end: the current partition bounds :returns: a modified new_surface that has the building lots set (also fills the self.building_coords list with tuples of coords to the corners of the building) """ x_start, x_end, z_start, z_end = self.get_partition_bounds(partition) # Random Growth Rate for the building lots growth_1 = rand_range(x_start, z_start, 2, 1) growth_2 = 3 - growth_1 # starting in center of yard corners = ((x_end - ((x_end - x_start) / 2), (z_end - (z_end - z_start) / 2)), (x_end - ((x_end - x_start) / 2), (z_end - (z_end - z_start) / 2))) # extend corners down and right until not valid, then back up one extension step while self.are_valid_corners(new_surface, corners): corners = ((corners[0][0] - growth_1, corners[0][1] - growth_2), (corners[1][0], corners[1][1])) corners = ((corners[0][0] + growth_1, corners[0][1] + growth_2), (corners[1][0], corners[1][1])) # extend corners up and left until not valid, then back up one extension step while self.are_valid_corners(new_surface, corners): corners = ((corners[0][0], corners[0][1]), (corners[1][0] + growth_2, corners[1][1] + growth_1)) corners = ((corners[0][0], corners[0][1]), (corners[1][0] - growth_2, corners[1][1] - growth_1)) building_lot_area = abs(corners[1][0] - corners[0][0]) * abs(corners[1][1] - corners[0][1]) if building_lot_area > YardGenerator.MIN_BUILDING_AREA: # if building lot of good size add to building coords and mark blocks in cells as buildings self.building_coords.append(corners) for i in range(corners[0][0], corners[1][0]): for j in range(corners[0][1], corners[1][1]): new_surface.surface_map[i][j].type = Block.BUILDING else: # else erase the entire yard as it is not able to hold a valid building lot for i in range(x_start, x_end): for j in range(z_start, z_end): new_surface.surface_map[i][j].type = Block.UNASSIGNED return new_surface