def expand_fixed_size_areas(self): """ Expand cell commands of the form 'd(20x20)' to their corresponding areas (in this example a 20x20 designation of d's) and mark those areas as plotted. """ label = self.label for y, row in enumerate(self.grid.rows): for x, cell in enumerate(row): # act on d(5x5) styles cells which haven't been plotted over m = re.match(r'(.+)\((\d+)x(\d+)\)', cell.command) if cell.plottable and m: command = m.group(1) width, height = (int(c) for c in m.group(2, 3)) area = Area((x, y), (x + width - 1, y + height - 1)) # ensure the grid is large enough to accept the expansion self.grid.expand_dimensions(x + width, y + height) # mark this area as plotted self.grid.set_area_cells(area, False, label, command) label = next_label(label) # set each corner's area variable for corner in area.corners: cornercell = self.grid.get_cell(*corner) cornercell.command = command cornercell.area = area self.label = label loglines('area', lambda: Grid.str_area_labels(self.grid)) return
def find_largest_area_from(self, x, y): """ Find the largest area that can be drawn with (x, y) as one of its corners. Returns the Area found, which will be at least 1x1 in size. """ # To start we build a list of direction pairs we'll want to test. # We need to check each compass direction paired with both # 90-degree rotations from each compass direction: NE, NW, EN, # ES, ... # These represent the 4 quadrants created by partitioning the grid # through the axes which pos sits on, and the inversions of each quad; # SE & ES is one such quad pair. Each quad overlaps at pos; # similarly, each quad shares two of its edges with adjacent quads. bestarea = Area((x, y), (x, y)) # find the biggest area(s) formable from each dir_pair quad for dirs in self.dir_pairs: area = self.find_largest_area_in_quad(x, y, dirs[0], dirs[1], bestarea) if area is not None: bestarea = area return bestarea
def setsize_build(self, start, end): """ Standard sizing mechanism for the build buildtype. Returns keys, pos: keys needed to make the currently-designating area the correct size pos is where the cursor ends up after sizing the area """ # move cursor halfway to end from start mid = midpoint(start, end) keys = self.move(start, mid) # resize construction area = Area(start, end) keys += ['{widen}'] * (area.width() - 1) keys += ['{heighten}'] * (area.height() - 1) return keys, mid
def discover_areas(self): """ Repeatedly plot the largest contiguous areas possible until there are no more areas left to plot. """ testarea = Area((0, 0), (self.grid.width - 1, self.grid.height - 1)) while True: loglines('area', lambda: Grid.str_area_labels(self.grid)) logmsg('area', 'Marking largest plottable areas starting ' + \ 'with label %s' % self.label) self.label = self.mark_largest_plottable_areas(self.label) # if every single cell is non-plottable (already plotted).. if not self.grid.is_area_plottable(testarea, True): logmsg('area', 'All areas discovered:') loglines('area', lambda: Grid.str_area_labels(self.grid)) return raise AreaPlotterError("Unable to plot all areas for unknown reason")
def find_largest_area_in_quad(self, x, y, dir1, dir2, bestarea): """ Given the quad starting at (x, y) and formed by dir1 and dir2 (treated as rays with (x, y) as origin), we find the max contiguous-cell distance along dir1, then for each position along dir1, we find the max contiguous-cell distance along dir2. This allows us to find the largest contiguous area constructable by travelling down dir1, then at a right angle along dir2 for each position. Returns the largest area found. """ command = self.grid.get_cell(x, y).command # Get the min/max size that this area may be, based on the command sizebounds = self.buildconfig.get('sizebounds', command) \ or (1, 1000, 1, 1000) # default sizebounds are very large # Get the max width of this area on the axis defined by # pos and dir1 direction, and max width from # the dir2. # width and height are conceptually aligned to an # east(dir1) x south(dir2) quad below. maxwidth = self.grid.count_contiguous_cells(x, y, dir1) maxheight = self.grid.count_contiguous_cells(x, y, dir2) if maxwidth < sizebounds[0]: # constructions narrower than the minimum width for this # command are ineligible to be any larger than 1 wide maxwidth = 1 elif maxwidth > sizebounds[1]: # don't let constructions be wider than allowed maxwidth = sizebounds[1] if maxheight < sizebounds[2]: # constructions shorter than the minimum height for this # command are ineligible to be any larger than 1 tall maxheight = 1 elif maxheight > sizebounds[3]: # don't let constructions be taller than allowed maxheight = sizebounds[3] if maxwidth * maxheight < bestarea.size(): return None # couldn't be larger than the best one yet found if maxheight == 1 and maxwidth == 1: # 1x1 area, just return it return Area((x, y), (x, y)) # (width x 1) sized area bestarea = Area((x, y), add_points((x, y), scale_point(dir1.delta(), maxwidth - 1))) for ydelta in range(1, maxheight): (xt, yt) = add_points((x, y), scale_point(dir2.delta(), ydelta)) height = ydelta + 1 width = self.grid.count_contiguous_cells(xt, yt, dir1) if width > maxwidth: # this row can't be wider than previous rows width = maxwidth elif width < maxwidth: # successive rows can't be wider than this row maxwidth = width if width * height > bestarea.size(): bestarea = Area((x, y), add_points((xt, yt), scale_point(dir1.delta(), width - 1))) else: continue return bestarea
def find_largest_area_in_quad(self, x, y, dir1, dir2, bestarea): """ Given the quad starting at (x, y) and formed by dir1 and dir2 (treated as rays with (x, y) as origin), we find the max contiguous-cell distance along dir1, then for each position along dir1, we find the max contiguous-cell distance along dir2. This allows us to find the largest contiguous area constructable by travelling down dir1, then at a right angle along dir2 for each position. Returns the largest area found. """ command = self.grid.get_cell(x, y).command # Get the min/max size that this area may be, based on the command sizebounds = self.buildconfig.get('sizebounds', command) \ or (1, 1000, 1, 1000) # default sizebounds are very large # Get the max width of this area on the axis defined by # pos and dir1 direction, and max width from # the dir2. # width and height are conceptually aligned to an # east(dir1) x south(dir2) quad below. maxwidth = self.grid.count_contiguous_cells(x, y, dir1) maxheight = self.grid.count_contiguous_cells(x, y, dir2) if maxwidth < sizebounds[0]: # constructions narrower than the minimum width for this # command are ineligible to be any larger than 1 wide maxwidth = 1 elif maxwidth > sizebounds[1]: # don't let constructions be wider than allowed maxwidth = sizebounds[1] if maxheight < sizebounds[2]: # constructions shorter than the minimum height for this # command are ineligible to be any larger than 1 tall maxheight = 1 elif maxheight > sizebounds[3]: # don't let constructions be taller than allowed maxheight = sizebounds[3] if maxwidth * maxheight < bestarea.size(): return None # couldn't be larger than the best one yet found if maxheight == 1 and maxwidth == 1: # 1x1 area, just return it return Area((x, y), (x, y)) # (width x 1) sized area bestarea = Area((x, y), add_points( (x, y), scale_point(dir1.delta(), maxwidth - 1) ) ) for ydelta in range(1, maxheight): (xt, yt) = add_points( (x, y), scale_point(dir2.delta(), ydelta) ) height = ydelta + 1 width = self.grid.count_contiguous_cells(xt, yt, dir1) if width > maxwidth: # this row can't be wider than previous rows width = maxwidth elif width < maxwidth: # successive rows can't be wider than this row maxwidth = width if width * height > bestarea.size(): bestarea = Area((x, y), add_points( (xt, yt), scale_point(dir1.delta(), width - 1) ) ) else: continue return bestarea
def __init__(self, name, convex, feature=[]): self.name = name Area.__init__(self, convex) Feature.__init__(self, feature)