def hitting_velocities(target: Rect) -> Iterable[Vector]: # brute force! we just need to establish some boundaries: # min x ... stall x from part 1 min_vx0 = triangular_root(target.left_x) # max x .... shoot directly to target right edge max_vx0 = target.right_x # min y ... shoot directly to target bottom # (note that target.top_y is actually bottom because y-axis is inverted) min_vy0 = target.top_y # max y ... use know-how from part 1 max_vy0 = -target.top_y - 1 velocities = Rect((min_vx0, min_vy0), (max_vx0, max_vy0)) return (v0 for v0 in velocities if does_hit(v0, target))
def draw_region(x: int, y: int, serial: int, square_size: int = 3, margin: int = 1) -> None: bounds = Rect((x - margin, y - margin), (x + square_size + margin - 1, y + square_size + margin - 1)) def cell(c_x: int, c_y: int) -> str: left, right = " ", " " if c_x == bounds.left_x: left = "" elif c_x == bounds.right_x: right = "" elif c_y in range(y, y + square_size): if c_x == x: left = "[" elif c_x == x + square_size - 1: right = "]" return f"{left}{power_level(c_x, c_y, serial):2}{right}" for dy in bounds.range_y(): print("".join(cell(dx, dy) for dx in bounds.range_x()))
def from_str(cls, line: str) -> 'Instruction': phrases = ('turn on', 'turn off', 'toggle') phrase = next(p for p in phrases if line.startswith(p + ' ')) rect_str = line[len(phrase):] x1, y1, x2, y2 = parse_line(rect_str, '$,$ through $,$') return cls(phrase, Rect((int(x1), int(y1)), (int(x2), int(y2))))
def target_area_from_text(text: str) -> Rect: # target area: x=20..30, y=-10..-5 x1, x2, y1, y2 = parse_line(text.strip(), 'target area: x=$..$, y=$..$') return Rect((int(x1), int(y1)), (int(x2), int(y2)))
def __init__(self, id_, left, top, width, height): self.id_ = int(id_) right_int = (left_int := int(left)) + int(width) - 1 bottom_int = (top_int := int(top)) + int(height) - 1 self.rect = Rect((left_int, top_int), (right_int, bottom_int))