def iter( self, limit_min: Optional[Point3D] = None, limit_max: Optional[Point3D] = None, ) -> Iterable[Point3D]: if limit_min is None: limit_min = self.min if limit_max is None: limit_max = self.max xs = range( max(limit_min.x, self.min.x), min(limit_max.x, self.max.x) + 1, ) ys = range( max(limit_min.y, self.min.y), min(limit_max.y, self.max.y) + 1, ) zs = range( max(limit_min.z, self.min.z), min(limit_max.z, self.max.z) + 1, ) for x in xs: for y in ys: for z in zs: yield Point3D(x, y, z)
def play(self) -> None: lines = list( filter( None, map( str.strip, """ on x=-46..7,y=-6..46,z=-50..-1 on x=-49..1,y=-3..46,z=-24..28 on x=2..47,y=-22..22,z=-23..27 on x=-27..23,y=-28..26,z=-21..29 on x=-39..5,y=-6..47,z=-3..44 on x=-30..21,y=-8..43,z=-13..34 on x=-22..26,y=-27..20,z=-29..19 off x=-48..-32,y=26..41,z=-47..-37 """.splitlines()))) texts = map( "\n".join, chain(*[ combinations(lines, length) for length in range(len(lines) + 1) ])) original_constraint = Region3D(Point3D(-50, -50, -50), Point3D(50, 50, 50)) mismatching_texts_and_values = ( (text, old_value, new_value) for text in texts for old_value in [Reactor.from_steps_text(text).cube_count] for new_value in [ len( Region3DSet.from_steps_text(text).intersect( original_constraint)), ] if old_value != new_value) first_mismatching_text_and_values = \ next(mismatching_texts_and_values, None) if not first_mismatching_text_and_values: print("All match!") return ( first_mismatching_text, first_mismatching_old_value, first_mismatching_new_value, ) = first_mismatching_text_and_values print(f"New {first_mismatching_new_value} " f"!= old {first_mismatching_old_value}") print(first_mismatching_text)
def from_step_text(cls, step_text: str) -> "RebootStep": """ >>> RebootStep.from_step_text("on x=-45..7,y=-17..27,z=5..49") RebootStep(min=Point3D(x=-45, y=-17, z=5), max=Point3D(x=7, y=27, z=49), set_to_on=True) >>> RebootStep.from_step_text("off x=-30..-17,y=-18..-5,z=-54..-31") RebootStep(min=Point3D(x=-30, y=-18, z=-54), max=Point3D(x=-17, y=-5, z=-31), set_to_on=False) """ set_to_on_str, *min_and_max_str = \ cls.re_step.match(step_text.strip()).groups() min_x, max_x, min_y, max_y, min_z, max_z = map(int, min_and_max_str) return cls( min=Point3D(min_x, min_y, min_z), max=Point3D(max_x, max_y, max_z), set_to_on=cls.SET_TO_ON_MAP[set_to_on_str], )
def from_robot_text(cls, robot_text): """ >>> Robot.from_robot_text("pos=<0,0,0>, r=4") Robot(position=Point3D(x=0, y=0, z=0), radius=4) """ x_str, y_str, z_str, radius_str = \ cls.re_robot.match(robot_text).groups() position = Point3D.from_int_texts(x_str, y_str, z_str) radius = int(radius_str) return cls(position, radius)
def __setitem__(self, key: Point3D, value: bool) -> None: value = bool(value) old_value = self[key] if old_value == value: return if value: if not key.is_bound(self.min, self.max): return self.cubes.add(key) else: self.cubes.remove(key)
class Reactor(Generic[RebootStepSetT]): cubes: Set[Point3D] = field(default_factory=set) min: Point3D = Point3D(-50, -50, -50) max: Point3D = Point3D(50, 50, 50) @classmethod def get_steps_class(cls) -> Type[RebootStepSetT]: return get_type_argument_class(cls, RebootStepSetT) @classmethod def from_steps_text( cls, steps_text: str, debugger: Debugger = Debugger(enabled=False), ) -> "Reactor": """ >>> Reactor.from_steps_text(''' ... on x=10..12,y=10..12,z=10..12 ... on x=11..13,y=11..13,z=11..13 ... off x=9..11,y=9..11,z=9..11 ... on x=10..10,y=10..10,z=10..10 ... ''').cube_count 39 >>> Reactor.from_steps_text(''' ... on x=-20..26,y=-36..17,z=-47..7 ... on x=-20..33,y=-21..23,z=-26..28 ... on x=-22..28,y=-29..23,z=-38..16 ... on x=-46..7,y=-6..46,z=-50..-1 ... on x=-49..1,y=-3..46,z=-24..28 ... on x=2..47,y=-22..22,z=-23..27 ... on x=-27..23,y=-28..26,z=-21..29 ... on x=-39..5,y=-6..47,z=-3..44 ... on x=-30..21,y=-8..43,z=-13..34 ... on x=-22..26,y=-27..20,z=-29..19 ... off x=-48..-32,y=26..41,z=-47..-37 ... on x=-12..35,y=6..50,z=-50..-2 ... off x=-48..-32,y=-32..-16,z=-15..-5 ... on x=-18..26,y=-33..15,z=-7..46 ... off x=-40..-22,y=-38..-28,z=23..41 ... on x=-16..35,y=-41..10,z=-47..6 ... off x=-32..-23,y=11..30,z=-14..3 ... on x=-49..-5,y=-3..45,z=-29..18 ... off x=18..30,y=-20..-8,z=-3..13 ... on x=-41..9,y=-7..43,z=-33..15 ... on x=-54112..-39298,y=-85059..-49293,z=-27449..7877 ... on x=967..23432,y=45373..81175,z=27513..53682 ... ''').cube_count 590784 """ steps_class = cls.get_steps_class() steps = steps_class.from_steps_text(steps_text) return cls().apply(steps, debugger=debugger) def __getitem__(self, item: Point3D) -> bool: return item in self.cubes def __setitem__(self, key: Point3D, value: bool) -> None: value = bool(value) old_value = self[key] if old_value == value: return if value: if not key.is_bound(self.min, self.max): return self.cubes.add(key) else: self.cubes.remove(key) @property def cube_count(self) -> int: return len(self.cubes) def apply( self, steps: RebootStepSetT, debugger: Debugger = Debugger(enabled=False), ) -> "Reactor": steps.apply(self, debugger=debugger) return self
def setPos(self,x,y,z): self.pos = Point3D(x,y,z)
def __init__(self): self.radius = 0.11 #m self.weight = 0.43 #kg self.pos = Point3D(0,0,0)