adventOfCode/challenges/2021/22-reactorReboot/py/__init__.py

77 lines
1.9 KiB
Python

from dataclasses import dataclass
from typing import Any, List, NamedTuple, Generator
from aocpy import BaseChallenge
MODE_ON = "on"
MODE_OFF = "off"
class Point(NamedTuple):
x: int
y: int
z: int
@dataclass
class Shape:
mode: str
p1: Point
p2: Point
def __init__(self, mode, x, y, z: str):
self.mode = mode
x1, x2 = [int(a) for a in x.split("..")]
y1, y2 = [int(a) for a in y.split("..")]
z1, z2 = [int(a) for a in z.split("..")]
self.p1 = Point(x1, y1, z1)
self.p2 = Point(x2, y2, z2)
def get_contained_points(self) -> Generator[Point, None, None]:
for x in range(self.p1.x, self.p2.x+1):
for y in range(self.p1.y, self.p2.y+1):
for z in range(self.p1.z, self.p2.z+1):
yield Point(x, y, z)
def parse(instr: str) -> List[Shape]:
o = []
for line in instr.strip().splitlines():
sp = line.split(" ")
x, y, z = [x.split("=")[-1] for x in sp[-1].split(",")]
o.append(Shape(sp[0], x, y, z))
return o
def is_point_out_of_bounds(p: Point) -> bool:
return not (-50 <= p.x <= 50 and -50 <= p.y <= 50 and -50 <= p.z <= 50)
class Challenge(BaseChallenge):
@staticmethod
def one(instr: str) -> int:
shapes = parse(instr)
points = {}
for shape in shapes:
if is_point_out_of_bounds(shape.p1) and is_point_out_of_bounds(shape.p2):
continue
for p in shape.get_contained_points():
if is_point_out_of_bounds(p):
continue
if (p in points) and (shape.mode == MODE_OFF):
del points[p]
elif (p not in points) and (shape.mode == MODE_ON):
points[p] = True
return len(points)
@staticmethod
def two(instr: str) -> Any:
raise NotImplementedError