refactored out Position
This commit is contained in:
parent
923e967056
commit
b83bb6b37a
12 changed files with 252 additions and 216 deletions
|
|
@ -8,17 +8,17 @@ day_num = 18
|
|||
|
||||
|
||||
def part1(lines: Iterator[str]) -> int:
|
||||
shower = Shower.create(Position.parse_all(lines))
|
||||
shower = Shower.create(Position3D.parse_all(lines))
|
||||
return shower.faces
|
||||
|
||||
|
||||
def part2(lines: Iterator[str]) -> int:
|
||||
shower = Shower.create(Position.parse_all(lines))
|
||||
shower = Shower.create(Position3D.parse_all(lines))
|
||||
return shower.faces - shower.count_trapped_droplets()
|
||||
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class Position:
|
||||
class Position3D:
|
||||
x: int
|
||||
y: int
|
||||
z: int
|
||||
|
|
@ -26,32 +26,32 @@ class Position:
|
|||
@classmethod
|
||||
def parse(cls, line: str) -> Self:
|
||||
x, y, z = line.split(",")
|
||||
return Position(int(x), int(y), int(z))
|
||||
return Position3D(int(x), int(y), int(z))
|
||||
|
||||
@classmethod
|
||||
def parse_all(cls, lines: Iterable[str]) -> Iterator[Self]:
|
||||
return (cls.parse(line) for line in lines)
|
||||
|
||||
def neighbors(self) -> Iterator[Position]:
|
||||
yield Position(self.x + 1, self.y, self.z)
|
||||
yield Position(self.x - 1, self.y, self.z)
|
||||
yield Position(self.x, self.y + 1, self.z)
|
||||
yield Position(self.x, self.y - 1, self.z)
|
||||
yield Position(self.x, self.y, self.z + 1)
|
||||
yield Position(self.x, self.y, self.z - 1)
|
||||
def neighbors(self) -> Iterator[Position3D]:
|
||||
yield Position3D(self.x + 1, self.y, self.z)
|
||||
yield Position3D(self.x - 1, self.y, self.z)
|
||||
yield Position3D(self.x, self.y + 1, self.z)
|
||||
yield Position3D(self.x, self.y - 1, self.z)
|
||||
yield Position3D(self.x, self.y, self.z + 1)
|
||||
yield Position3D(self.x, self.y, self.z - 1)
|
||||
|
||||
def min_max(self, mm: tuple[Position, Position] | None) -> tuple[Position, Position]:
|
||||
def min_max(self, mm: tuple[Position3D, Position3D] | None) -> tuple[Position3D, Position3D]:
|
||||
if mm is None:
|
||||
return self, self
|
||||
|
||||
return (Position(min(mm[0].x, self.x),
|
||||
min(mm[0].y, self.y),
|
||||
min(mm[0].z, self.z)),
|
||||
Position(max(mm[1].x, self.x),
|
||||
max(mm[1].y, self.y),
|
||||
max(mm[1].z, self.z)))
|
||||
return (Position3D(min(mm[0].x, self.x),
|
||||
min(mm[0].y, self.y),
|
||||
min(mm[0].z, self.z)),
|
||||
Position3D(max(mm[1].x, self.x),
|
||||
max(mm[1].y, self.y),
|
||||
max(mm[1].z, self.z)))
|
||||
|
||||
def is_between(self, min: Position, max: Position) -> bool:
|
||||
def is_between(self, min: Position3D, max: Position3D) -> bool:
|
||||
return (min.x <= self.x <= max.x
|
||||
and min.y <= self.y <= max.y
|
||||
and min.z <= self.z <= max.z)
|
||||
|
|
@ -65,12 +65,12 @@ class DropletType(Enum):
|
|||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class Shower:
|
||||
droplets: dict[Position, tuple[DropletType, int]]
|
||||
droplets: dict[Position3D, tuple[DropletType, int]]
|
||||
faces: int
|
||||
|
||||
@classmethod
|
||||
def create(cls, positions: Iterable[Position]) -> Self:
|
||||
droplets: dict[Position, tuple[DropletType, int]] = {}
|
||||
def create(cls, positions: Iterable[Position3D]) -> Self:
|
||||
droplets: dict[Position3D, tuple[DropletType, int]] = {}
|
||||
faces = 0
|
||||
for position in positions:
|
||||
candidate = droplets.get(position)
|
||||
|
|
@ -95,14 +95,14 @@ class Shower:
|
|||
|
||||
def count_trapped_droplets(self) -> int:
|
||||
droplets = self.droplets.copy()
|
||||
minmax: tuple[Position, Position] | None = None
|
||||
minmax: tuple[Position3D, Position3D] | None = None
|
||||
for position in droplets.keys():
|
||||
minmax = position.min_max(minmax)
|
||||
if minmax is None:
|
||||
raise Exception("I got no data to work with")
|
||||
min_values, max_values = minmax
|
||||
|
||||
todo: list[Position] = [min_values]
|
||||
todo: list[Position3D] = [min_values]
|
||||
while todo:
|
||||
current = todo[0]
|
||||
todo = todo[1:]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from advent.common import input
|
||||
|
||||
from .solution import Position, Shower, day_num, part1, part2
|
||||
from .solution import Position3D, Shower, day_num, part1, part2
|
||||
|
||||
|
||||
def test_part1():
|
||||
|
|
@ -20,19 +20,19 @@ def test_part2():
|
|||
def test_simple_count():
|
||||
lines = ["1,1,1", "1,1,2"]
|
||||
expected = 10
|
||||
result = Shower.create(Position.parse_all(lines))
|
||||
result = Shower.create(Position3D.parse_all(lines))
|
||||
assert result.faces == expected
|
||||
|
||||
|
||||
def test_example_faces():
|
||||
lines = input.read_lines(day_num, 'example01.txt')
|
||||
expected = 64
|
||||
result = Shower.create(Position.parse_all(lines))
|
||||
result = Shower.create(Position3D.parse_all(lines))
|
||||
assert result.faces == expected
|
||||
|
||||
|
||||
def test_example_trapped():
|
||||
lines = input.read_lines(day_num, 'example01.txt')
|
||||
expected = 6
|
||||
result = Shower.create(Position.parse_all(lines))
|
||||
result = Shower.create(Position3D.parse_all(lines))
|
||||
assert result.count_trapped_droplets() == expected
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue