def draw_coordinates( coordinates: Iterable[Pos], including_areas: bool = False, distance_limit: int = None, bounds: Rect = Rect.at_origin(10, 10), empty_char: str = '·', safe_char: str = '#', ) -> None: coordinates_list = list(coordinates) # draw points canvas = dict(zip(coordinates_list, string.ascii_uppercase)) if including_areas: # draw claims for part 1 areas = claim_areas(coordinates_list, include_infinite=True) canvas.update((area_pos, canvas[pos].lower()) for pos, area in areas.items() for area_pos in area if area_pos not in canvas) elif distance_limit is not None: # draw safe region for part 2 region = safe_region(coordinates_list, distance_limit) canvas.update((pos, safe_char) for pos in region if pos not in canvas) for y in bounds.range_y(): print("".join( canvas.get((x, y), empty_char) for x in bounds.range_x()))
def from_lines(cls, lines: Iterable[str]): height, width = 0, None trees: set[Pos] = set() for y, line in enumerate(lines): line = line.strip() assert all(ch in (cls.TREE_CHAR, cls.OPEN_CHAR) for ch in line) height += 1 if width is None: # width is determined by the length of the first line width = len(line) else: # all lines must have the equal length assert width == len(line) trees.update( (x, y) for x, ch in enumerate(line) if ch == cls.TREE_CHAR ) if width is None: raise ValueError("no lines") return cls( trees=trees, bounds=Rect.at_origin(width=width, height=height) )
def load(cls, fn: str): with open(fn) as file: lines = [line.rstrip() for line in file] height = len(lines) assert height > 0 width = single_value(set(len(line) for line in lines)) board = {(x, y): c for y, line in enumerate(lines) for x, c in enumerate(line)} return cls(board, Rect.at_origin(width, height))
def __init__(self, width: int, height: int, lights_on: Iterable[Pos], *, lights_stuck_on: Iterable[Pos] = ()): assert width > 0 assert height > 0 self.bounds = Rect.at_origin(width, height) self.lights_stuck_on = set(lights_stuck_on) self.lights_on = set(lights_on) | self.lights_stuck_on assert all(pos in self.bounds for pos in self.lights_on) assert all(pos in self.bounds for pos in self.lights_stuck_on)
def __init__(self, width: int = 50, height: int = 6, pixels_on: Iterable[Pos] = None): self.bounds = Rect.at_origin(width, height) self.pixels_on: set[Pos] = set(pixels_on) if pixels_on else set()
except StopIteration as stop: raise KeyError(letter) from stop @classmethod def from_path(cls, path: str) -> Iterable['Direction']: return (cls.from_letter(letter) for letter in path) def __add__(self, other): x, y = other return x + self.dx, y + self.dy def __radd__(self, other): return self + other BOUNDS = Rect.at_origin(4, 4) def walk(path: str, start: Pos = BOUNDS.top_left) -> Pos: pos = start for step in Direction.from_path(path): pos += step assert pos in BOUNDS return pos class Room(): def __init__(self, path: str = '', pos: Pos = None): self.path = path