Пример #1
0
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}')
Пример #2
0
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()))
Пример #3
0
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)
Пример #4
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())
Пример #5
0
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()))