aocpy/2021/d22.py
2024-11-30 12:22:44 -05:00

93 lines
2.5 KiB
Python

from lib import get_data
from lib import ints
from dataclasses import dataclass
from typing import Optional
data = get_data(__file__)
limit = 50
ps = set()
for i, line in enumerate(data.splitlines()):
x_min, x_max, y_min, y_max, z_min, z_max = ints(line)
for x in range(max(x_min, -limit), min(x_max, limit) + 1):
for y in range(max(y_min, -limit), min(y_max, limit) + 1):
for z in range(max(z_min, -limit), min(z_max, limit) + 1):
if line.startswith("on"):
ps.add((x, y, z))
elif line.startswith("off"):
if (x, y, z) in ps:
ps.remove((x, y, z))
else:
assert False
print(len(ps))
@dataclass
class Line:
a: int
b: int
def intersects(self, other: "Line") -> bool:
return self.b > other.a and self.a < other.b
def intersection(self, other: "Line") -> Optional["Line"]:
if not self.intersects(other):
return None
return Line(max(self.a, other.a), min(self.b, other.b))
def length(self) -> int:
assert self.b > self.a
return self.b - self.a + 1
@dataclass(frozen=True)
class Cube:
on: bool
x: Line
y: Line
z: Line
@classmethod
def from_line(cls, line: str) -> "Cube":
xs = ints(line)
assert len(xs) == 6
lines = [Line(*xs[i:i+2]) for i in range(0, len(xs), 2)]
on = True if line.startswith("on") else False
return Cube(on, *lines)
def volume(self) -> int:
return (self.x.length() * self.y.length() * self.z.length()) * (1 if self.on else -1)
def intersects(self, other: "Cube") -> bool:
return (
self.x.intersects(other.x)
and self.y.intersects(other.y)
and self.z.intersects(other.z)
)
def intersection(self, other: "Cube") -> Optional["Cube"]:
x = self.x.intersection(other.x)
y = self.y.intersection(other.y)
z = self.z.intersection(other.z)
if x is None or y is None or z is None:
return None
return Cube(not self.on, x, y, z)
# Inclusion/exclusion principle from set theory
cubes = []
for line in data.splitlines():
cc = Cube.from_line(line)
ncubes = []
for i in range(len(cubes)):
c = cubes[i]
ic = c.intersection(cc)
if ic is not None:
cubes.append(ic)
if cc.on:
cubes.append(cc)
print(sum(c.volume() for c in cubes))