def with_zero_x(self) -> "Area":
     cls = type(self)
     # noinspection PyArgumentList
     return cls(
         min=Point2D(0, self.min.y),
         max=Point2D(0, self.max.y),
     )
Example #2
0
 def __str__(self) -> "str":
     """
     >>> print(Region2DSet())
     >>> print(Region2DSet([Region2D(Point2D(0, 0), Point2D(2, 2))]))
     (0, 0)
     ###
     ###
     ###
     """
     if not self.regions:
         return ""
     min_coordinates, _ = min_and_max_tuples(region.min
                                             for region in self.regions)
     min_point = Point2D(min_coordinates)
     _, max_coordinates = min_and_max_tuples(region.max
                                             for region in self.regions)
     max_point = Point2D(max_coordinates)
     counts = {}
     for point in self:
         counts.setdefault(point, 0)
         counts[point] += 1
     return "{min_point}\n{as_string}".format(
         min_point=tuple(min_point),
         as_string="\n".join("".join(
             "#" if count == 1 else str(count) if count > 1 else "."
             for x in range(min_point.x, max_point.x + 1)
             for point in [Point2D(x, y)]
             for count in [counts.get(point, 0)])
                             for y in range(min_point.y, max_point.y + 1)),
     )
    def play(self) -> None:
        launch = Launch.from_area_text(self.input)
        for y in range(0, 150):
            highest_y = launch\
                .get_highest_y_for_initial_y_that_lands_in_area_y(y)
            print(f"For y={y}: max={highest_y}")

        click.prompt("Visualise throw? Press any button")
        click.getchar()

        other_launch = Launch.from_area_text(
            "target area: x=20..30, y=-10..-5"
        )
        print(launch)
        initial_velocity: Point2D = Point2D(0, 0)
        while True:
            click.echo(f"Move initial velocity {initial_velocity}")
            char = click.getchar("Tell")
            if char == "q":
                break
            elif char == "s":
                launch, other_launch = other_launch, launch
            elif char in self.OFFSET_MAP:
                initial_velocity = initial_velocity.offset(
                    self.OFFSET_MAP[char],
                )
            else:
                continue
            launch.set_path_from(Point2D(0, 0), initial_velocity)
            print(launch)
Example #4
0
 def pad(self, count: int) -> "Area":
     cls = type(self)
     # noinspection PyArgumentList
     return cls(
         min=Point2D(self.min.x - count, self.min.y + count),
         max=Point2D(self.max.x - count, self.max.y + count),
     )
    def from_area_text(cls, area_text: str) -> "Area":
        """
        >>> Area.from_area_text("target area: x=253..280, y=-73..-46")
        Area(min=Point2D(x=253, y=-73), max=Point2D(x=280, y=-46))
        """
        min_x, max_x, min_y, max_y = \
            map(int, cls.re_area.match(area_text).groups())

        return cls(min=Point2D(min_x, min_y), max=Point2D(max_x, max_y))
Example #6
0
class Challenge(BaseChallenge):
    def solve(self, _input, debugger: Debugger):
        """
        >>> Challenge().default_solve()
        261
        """
        return 261
        node_set = NodeSetExtended.from_nodes_text(_input)
        if debugger:
            print(node_set.show())
        return Solver().get_minimum_solution_length(
            node_set, debugger=debugger)

    OFFSETS = {
        '\x1b[A': Point2D(0, -1),
        '\x1b[D': Point2D(-1, 0),
        '\x1b[B': Point2D(0, 1),
        '\x1b[C': Point2D(1, 0),
    }

    def play(self):
        initial_node_set = NodeSetExtended.from_nodes_text(self.input)
        node_set = initial_node_set
        position = node_set.position
        empty_spot = node_set.get_empty_spot()
        distances_by_position_and_empty = {(position, empty_spot): 0}
        while True:
            print(node_set.show())
            position = node_set.position
            empty_spot = node_set.get_empty_spot()
            distance = distances_by_position_and_empty[(position, empty_spot)]
            print(
                f"At {position} after {distance} moves, use arrow "
                f"keys to move empty from {empty_spot}, or r to reset: ")
            key = click.getchar()
            if key == 'r':
                node_set = initial_node_set
            elif key in self.OFFSETS:
                offset = self.OFFSETS[key]
                new_empty_spot = empty_spot.offset(offset)
                if not node_set.can_move_positions(new_empty_spot, empty_spot):
                    print(f"Cannot move from {empty_spot} to {new_empty_spot}")
                    continue
                node_set = node_set.move_positions(new_empty_spot, empty_spot)
                new_position = node_set.position
                new_distance = distance + 1
                existing_distance = distances_by_position_and_empty\
                    .get((new_position, new_empty_spot))
                if existing_distance is None \
                        or existing_distance > new_distance:
                    distances_by_position_and_empty[
                        (new_position, new_empty_spot)] = new_distance
            else:
                print(f"Unknown key {repr(key)}")
 def iterate_path(
     self, initial_position: Point2D, initial_velocity: Point2D,
 ) -> Iterable[Tuple[Point2D, Point2D]]:
     positions_and_velocities = zip(
         self.iterate_x_path(initial_position, initial_velocity),
         self.iterate_y_path(initial_position, initial_velocity),
     )
     for (x, v_x), (y, v_y) in positions_and_velocities:
         position = Point2D(x, y)
         velocity = Point2D(v_x, v_y)
         yield position, velocity
Example #8
0
    def solve(self, _input, debug=False):
        """
        >>> Challenge().default_solve()
        90
        """
        maze = Maze(int(_input))
        solution = maze.solve(Point2D(1, 1), Point2D(31, 39))
        if debug:
            print(maze.show(solution=solution))

        return len(solution) - 1
Example #9
0
 def loop(self):
     center = Point2D(self.width / 2, self.height / 2)
     offset = Point2D(0, 0)
     self.hilbert(center, 1, offset, Step(Step.CONST_DIRECTION_D))
     if self._load_image_flag is True:
         pygame.image.save(self.canvas, self.save_name)
     while self._continue_flag is True:
         # self.canvas.fill(self.BACKGROUND_COLOR)
         pygame.display.flip()
         self.handle_events()
         pass
Example #10
0
 def try_parse(cls, text: str):
     """
     >>> Toggle.try_parse("toggle 461,550 through 564,900")
     Toggle(start=Point2D(x=461, y=550), end=Point2D(x=564, y=900))
     >>> Instruction.parse("toggle 461,550 through 564,900")
     Toggle(start=Point2D(x=461, y=550), end=Point2D(x=564, y=900))
     """
     match = cls.re_toggle.match(text)
     if not match:
         return None
     start_x, start_y, end_x, end_y = map(int, match.groups())
     return cls(Point2D(start_x, start_y), Point2D(end_x, end_y))
Example #11
0
 def draw_line(self, _from: Point2D, to: Point2D):
     if (_from.is_empty()):
         return
     if self._load_image_flag is False:
         self.color.hsva = (interp(self.count, [0, self.number_of_lines],
                                   [0, 360]), 100, 100)
     else:
         self.color = tuple(self._image_pixels_color_array[int(to.y)][int(
             to.x)])
     pygame.draw.line(self.canvas, self.color, _from.to_tuple(),
                      to.to_tuple(), 2)
     self.count += 1
    def get_xs_that_land_in_area_for_initial_y(
        self,
        initial_y: int,
    ) -> Iterable[int]:
        if Point2D(0, self.area.min.y) in self.area:
            xs = range(self.area.min.x, self.area.max.x + 1)
        elif self.area.min.x > 0:
            min_x = math.floor((-1 + math.sqrt(1 + 8 * self.area.min.x)) / 2)
            xs = range(min_x, min_x + 500)
        else:
            max_x = math.floor((-1 - math.sqrt(1 + 8 * self.area.min.x)) / 2)
            xs = range(max_x, max_x - 500, -1)

        return (x for x in xs
                if self.does_path_land_in_area(Point2D(x, initial_y)))
 def from_cavern_text(cls, cavern_text: str) -> "Cavern":
     """
     >>> print(Cavern.from_cavern_text('''
     ...     1163751742
     ...     1381373672
     ...     2136511328
     ...     3694931569
     ...     7463417111
     ...     1319128137
     ...     1359912421
     ...     3125421639
     ...     1293138521
     ...     2311944581
     ... '''))
     1163751742
     1381373672
     2136511328
     3694931569
     7463417111
     1319128137
     1359912421
     3125421639
     1293138521
     2311944581
     """
     lines = filter(None, map(str.strip, cavern_text.splitlines()))
     return cls(risks={
         Point2D(x, y): int(risk_str)
         for y, line in enumerate(lines) for x, risk_str in enumerate(line)
     }, )
 def from_printed_sheet(cls, sheet_printout: str) -> "Sheet":
     """
     >>> print(":", Sheet.from_printed_sheet('''
     ...     #####
     ...     #...#
     ...     #...#
     ...     #...#
     ...     #####
     ... '''))
     : #####
     #...#
     #...#
     #...#
     #####
     """
     lines = filter(None, map(str.strip, sheet_printout.splitlines()))
     return cls(
         dots={
             Point2D(x, y)
             for y, line
             in enumerate(lines)
             for x, character in enumerate(line)
             if character == "#"
         },
     )
Example #15
0
 def move_direction(self, direction: DirectionEnum) -> "Herd":
     offset = self.OFFSET_MAP[direction]
     cls = type(self)
     # noinspection PyArgumentList
     return cls(
         cucumbers={
             point: (
                 None
                 if (
                     self.cucumbers[point] == direction
                     and self.cucumbers[next_point] is None
                 ) else
                 self.cucumbers[previous_point]
                 if (
                     self.cucumbers[point] is None
                     and self.cucumbers[previous_point] == direction
                 ) else
                 self.cucumbers[point]
             )
             for y in range(self.size.y)
             for x in range(self.size.x)
             for point in [Point2D(x, y)]
             for next_point in [self.get_next_point(point, offset)]
             for previous_point in [self.get_previous_point(point, offset)]
         },
         size=self.size,
     )
Example #16
0
    def hilbert(self, center: Point2D, current_order: int, previous: Point2D,
                direction: Step):
        if self._continue_flag is False:
            return
        if (self.number_of_iterations >= self.render_steps):
            self.number_of_iterations = 0
            pygame.display.flip()
            self.clock.tick(self.fps)
            self.handle_events()
        else:
            self.number_of_iterations += 1

        number_of_sides = 2**(current_order - 1)
        x_offset = self.width / (number_of_sides * 2)
        y_offset = self.height / (number_of_sides * 2)
        offset = Point2D(x_offset, y_offset)

        if (current_order is self.order):
            trace = self.trace_path_by_direction(center, offset, direction)

            return self.draw_shape(previous, trace.first, trace.second,
                                   trace.third, trace.fourth)
        else:
            trace = self.trace_path_by_direction(center, offset, direction)

            first_point = self.hilbert(trace.first, current_order + 1,
                                       previous, trace.path.get(0))
            second_point = self.hilbert(trace.second, current_order + 1,
                                        first_point, trace.path.get(1))
            third_point = self.hilbert(trace.third, current_order + 1,
                                       second_point, trace.path.get(2))
            fourth_point = self.hilbert(trace.fourth, current_order + 1,
                                        third_point, trace.path.get(3))

            return fourth_point
Example #17
0
 def set_default_position(self):
     """
     >>> NodeSetExtended.from_nodes_text(
     ...     "root@ebhq-gridcenter# df -h\\n"
     ...     "Filesystem              Size  Used  Avail  Use%\\n"
     ...     "/dev/grid/node-x0-y0     88T   66T    22T   75%\\n"
     ...     "/dev/grid/node-x0-y1     85T   65T    20T   76%\\n"
     ...     "/dev/grid/node-x0-y2     88T   67T    21T   76%\\n"
     ... )
     NodeSetExtended(nodes={Point2D(x=0, y=0):
         Node(position=Point2D(x=0, y=0), size=88, used=66),
         Point2D(x=0, y=1):
             Node(position=Point2D(x=0, y=1), size=85, used=65),
         Point2D(x=0, y=2):
             Node(position=Point2D(x=0, y=2), size=88, used=67)},
         position=Point2D(x=0, y=0))
     >>> NodeSetExtended.from_nodes_text(
     ...     "root@ebhq-gridcenter# df -h\\n"
     ...     "Filesystem            Size  Used  Avail  Use%\\n"
     ...     "/dev/grid/node-x0-y0   10T    8T     2T   80%\\n"
     ...     "/dev/grid/node-x0-y1   11T    6T     5T   54%\\n"
     ...     "/dev/grid/node-x0-y2   32T   28T     4T   87%\\n"
     ...     "/dev/grid/node-x1-y0    9T    7T     2T   77%\\n"
     ...     "/dev/grid/node-x1-y1    8T    0T     8T    0%\\n"
     ...     "/dev/grid/node-x1-y2   11T    7T     4T   63%\\n"
     ...     "/dev/grid/node-x2-y0   10T    6T     4T   60%\\n"
     ...     "/dev/grid/node-x2-y1    9T    8T     1T   88%\\n"
     ...     "/dev/grid/node-x2-y2    9T    6T     3T   66%\\n"
     ... ).position
     Point2D(x=2, y=0)
     """
     if self.position is NotImplemented:
         max_x = max(node.position.x for node in self.nodes.values())
         self.position = Point2D(max_x, 0)
Example #18
0
 def from_image_text(cls, image_text: str) -> "Image":
     """
     >>> print(":", Image.from_image_text('''
     ...     #..#.
     ...     #....
     ...     ##..#
     ...     ..#..
     ...     ..###
     ... '''))
     : .......
     .#..#..
     .#.....
     .##..#.
     ...#...
     ...###.
     .......
     """
     lines = filter(None, map(str.strip, image_text.splitlines()))
     light_pixels = {
         point
         for y, line in enumerate(lines)
         for x, character in enumerate(line)
         for point in [Point2D(x, y)]
         if character == "#"
     }
     return cls(
         light_pixels=light_pixels,
         boundary=Area.from_points(light_pixels),
         default_out_of_boundary=False,
     )
 def with_zero_x_area(self) -> "Launch":
     cls = type(self)
     # noinspection PyArgumentList
     return cls(
         area=self.area.with_zero_x(),
         path=[Point2D.get_zero_point()],
     )
Example #20
0
    def turn_corners_on(self):
        (min_x, min_y), (max_x, max_y) = min_and_max_tuples(self.grid)
        for x in (min_x, max_x):
            for y in (min_y, max_y):
                self.grid[Point2D(x, y)] = True

        return self
Example #21
0
 def standard_9_buttons(cls):
     # noinspection PyArgumentList
     return cls({
         Point2D(0, 0): '1',
         Point2D(1, 0): '2',
         Point2D(2, 0): '3',
         Point2D(0, 1): '4',
         Point2D(1, 1): '5',
         Point2D(2, 1): '6',
         Point2D(0, 2): '7',
         Point2D(1, 2): '8',
         Point2D(2, 2): '9',
     })
    def get_highest_y_for_initial_y_that_lands_in_area_y(
        self, initial_y: int,
    ) -> Optional[int]:
        if not (self.area.min.x == self.area.max.x == 0):
            return self\
                .with_zero_x_area()\
                .get_highest_y_for_initial_y_that_lands_in_area_y(initial_y)

        path = self.generate_path(
            Point2D.get_zero_point(),
            Point2D(0, initial_y),
        )
        last_point = path[-1]
        if last_point not in self.area:
            return None
        _, (_, max_y) = min_and_max_tuples(path)
        return max_y
 def __str__(self) -> "str":
     return "\n".join(
         "".join(self.amphipod_map[position_name].value if position_name in
                 self.amphipod_map else "#" if character == "#" else "."
                 for x, character in enumerate(line)
                 for position in [Point2D(x, y)] for position_name in
                 [DeepPositionNameEnum.maybe_from_position(position)])
         for y, line in enumerate(DeepPositionNameEnum.MAZE_LINES))
Example #24
0
    def __contains__(self, item: Union[tuple, Point2D]) -> bool:
        item = Point2D(item)
        if not (0 <= item.y < len(self.levels)):
            return False
        if not (0 <= item.x < len(self.levels[item.y])):
            return False

        return True
Example #25
0
 def generate_rays(self, precision):
     self.precision = precision
     angle = atan2(self.direction.y, self.direction.x)
     _from = angle - self.fov / 2
     to = angle + self.fov / 2
     for i in range(0, precision):
         _angle = interp(i, [0, precision], [_from, to])
         self.rays.append(Ray(self, Point2D(cos(_angle), sin(_angle))))
Example #26
0
 def update_distances(updated_point):
     x, z = updated_point.x, updated_point.z
     if x + 1 < self.width:
         update_distance(updated_point, Point2D(x + 1, z), neighbors)
         """if z + 1 < self.length:
             update_distance(updated_point, Point2D(x + 1, z + 1), neighbors)
         if z - 1 >= 0:
             update_distance(updated_point, Point2D(x + 1, z - 1), neighbors)"""
     if x - 1 >= 0:
         update_distance(updated_point, Point2D(x - 1, z), neighbors)
         """if z + 1 < self.length:
             update_distance(updated_point, Point2D(x - 1, z + 1), neighbors)
         if z - 1 >= 0:
             update_distance(updated_point, Point2D(x - 1, z - 1), neighbors)"""
     if z + 1 < self.length:
         update_distance(updated_point, Point2D(x, z + 1), neighbors)
     if z - 1 >= 0:
         update_distance(updated_point, Point2D(x, z - 1), neighbors)
 def __str__(self) -> str:
     (min_x, max_x), (min_y, max_y) = self.get_bounding_box()
     return "\n".join(
         "".join(
             "#" if self[Point2D(x, y)] else "."
             for x in range(min_x, max_x + 1)
         )
         for y in range(min_y, max_y + 1)
     )
Example #28
0
 def solve(self, _input, debug=False):
     """
     >>> Challenge().default_solve()
     135
     """
     maze = part_a.Maze(int(_input))
     if debug:
         for depth in [0, 1, 2, 49]:
             seen = MazeSolverExtended()\
                 .flood(maze, Point2D(1, 1), depth, debug=debug)
             print(f"Depth: {depth}, seen: {len(seen)}")
             print(maze.show(solution=seen))
     seen_50 = MazeSolverExtended()\
         .flood(maze, Point2D(1, 1), 50, debug=debug)
     if debug:
         print(f"Depth: 50, seen: {len(seen_50)}")
         print(maze.show(solution=seen_50))
     return len(seen_50)
Example #29
0
 def try_parse(cls, text: str):
     """
     >>> Turn.try_parse("turn off 370,39 through 425,839")
     Turn(offset=-1, start=Point2D(x=370, y=39), end=Point2D(x=425, y=839))
     >>> Turn.try_parse("turn on 370,39 through 425,839")
     Turn(offset=1, start=Point2D(x=370, y=39), end=Point2D(x=425, y=839))
     >>> Instruction.parse("turn off 370,39 through 425,839")
     Turn(offset=-1, start=Point2D(x=370, y=39), end=Point2D(x=425, y=839))
     >>> Instruction.parse("turn on 370,39 through 425,839")
     Turn(offset=1, start=Point2D(x=370, y=39), end=Point2D(x=425, y=839))
     """
     match = cls.re_toggle.match(text)
     if not match:
         return None
     offset_str, *coordinate_strs = match.groups()
     offset = cls.ON_MAP[offset_str]
     start_x, start_y, end_x, end_y = map(int, coordinate_strs)
     return cls(offset, Point2D(start_x, start_y), Point2D(end_x, end_y))
Example #30
0
 def update_distances(updated_point):
     x0, z0 = updated_point.x, updated_point.z
     for xn, zn in product(xrange(x0 - 1, x0 + 2),
                           xrange(z0 - 1, z0 + 2)):
         if (
                 xn != x0 or zn != z0
         ) and 0 <= xn < W and 0 <= zn < L and distance_map[xn,
                                                            zn] > 0:
             update_distance(updated_point, Point2D(xn, zn))