93 lines
2.5 KiB
Python
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))
|