def draw_map(seed: int, region: Rect, *, highlighted: Iterable[Pos] = (), char_space='·', char_wall='#', char_highlighted='O') -> None: highlighted = set(highlighted) def char(pos: Pos) -> str: if pos in highlighted: return char_highlighted elif is_wall(seed, pos): return char_wall else: return char_space assert region.width <= 10 assert region.height <= 10 x_coor = "".join(str(x)[-1] for x in region.range_x()) print(f" {x_coor}") for y in region.range_y(): row = ''.join(char((x, y)) for x in region.range_x()) print(f'{y} {row}')
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 highest_y(target: Rect) -> tuple[int, Vector]: """ Finds the initial velocity to hit the target while reaching the highest possibly `y`. """ # find any `vx_0` that will eventually stall to `vx=0` when `x` is in the target x range # e.g. target x=12..20 # - vx_0=4 (0:4, 4:3, 7:2, 9:1, 10:0) doesn't reach # - vx_0=5 (0:5, 5:4, 9:3, 12:2, 14:1, 15:0) stalls at x=15 ok # - vx_0=6 (0:6, 6:5, 11:4, 15:3, 18:2, 20:1, 21:0) overshoot vx_0 = triangular_root(target.left_x) + 1 if not triangular(vx_0) in target.range_x(): # not possible to "stall" x in target area -> still possible to shoot into target, but # this calculation is not supported raise ValueError(f"unable to stall x in {target.range_x()}") # one step after the projectile returns to `y=0`, it will hit the bottom of the target y range # e.g. target y=-20..-30 # -> vy_0=28 (0:28, 28:27, 55:26, ..., 405:1, tr(28)=406:0, 406:-1, ..., 0:-29, -29:-30) hit # -> vy_0=29 (0:29, 29:28, 57:27, ..., 434:1, tr(29)=435:0, 435:-1, ..., 0:-30, -30:-31) hit # -> vy_0=30 (0:30, 30:29, 59:28, ..., 464:1, tr(30)=465:0, 465:-1, ..., 0:-31, -31:-32) miss # => max_y=435 using vy_0=29 (tr(29)=435) # target.top_y is actually the bottom part of the target because y-axis is inverted assert target.top_y < 0 vy_0 = -target.top_y - 1 max_y = triangular(vy_0) return max_y, (vx_0, vy_0)
def drawn(stars: Stars, bounds: Rect = None, char_star='*', char_sky='·') -> str: positions = set(tuple(pos) for pos, _ in stars) if bounds is None: bounds = Rect.with_all((x, y) for x, y in positions) return "\n".join(''.join(char_star if (x, y) in positions else char_sky for x in bounds.range_x()) for y in bounds.range_y())
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()))