Files
adventofcode-2021/day05/day05.py
Alek Ratzloff c8c3c0dfcd Add day 4, 5, and 6
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2021-12-07 11:15:07 -08:00

98 lines
2.9 KiB
Python
Executable File

#!/usr/bin/env python3
from collections import defaultdict
import dataclasses
import sys
from typing import DefaultDict, Generator, Sequence, Tuple
import re
from itertools import repeat
import pprint
SEG_PAT = re.compile(r"(?P<x1>[\d]+),(?P<y1>[\d]+) -> (?P<x2>[\d]+),(?P<y2>[\d]+)")
@dataclasses.dataclass
class Seg:
x1: int
y1: int
x2: int
y2: int
@staticmethod
def from_str(s: str) -> "Seg":
match = SEG_PAT.match(s)
assert match
return Seg(
int(match["x1"]), int(match["y1"]), int(match["x2"]), int(match["y2"])
)
def points(self, diag: bool) -> Generator[Tuple[int, int], None, None]:
if self.x1 == self.x2:
# We're going up and down
if self.y1 > self.y2:
lo = self.y2
hi = self.y1
else:
lo = self.y1
hi = self.y2
yield from zip(repeat(self.x1), range(lo, hi + 1))
elif self.y1 == self.y2:
# We're going side to side
if self.x1 > self.x2:
lo = self.x2
hi = self.x1
else:
lo = self.x1
hi = self.x2
yield from zip(range(lo, hi + 1), repeat(self.y1))
elif diag:
# Figure out the slope
if self.x1 > self.x2:
# right to left
lox = self.x2
hix = self.x1
loy = self.y2
hiy = self.y1
else:
lox = self.x1
hix = self.x2
loy = self.y1
hiy = self.y2
slope = float(hiy - loy) / float(hix - lox)
yf = float(loy)
for x in range(lox, hix + 1):
yield (x, int(yf))
yf += slope
else:
# No support for diagonals
return None
def part1(segments: Sequence[Seg]):
# Create a counting dict, we can probably avoid the matrix stuff
points: DefaultDict[Tuple[int, int], int] = defaultdict(lambda: 0)
for seg in segments:
for point in seg.points(diag=False):
points[point] += 1
# Figure out how many locations where at least 2 lines overlap
count = len([overlap for overlap in points.values() if overlap > 1])
print(f"{count} overlaps >1")
def part2(segments: Sequence[Seg]):
# Create a counting dict, we can probably avoid the matrix stuff
points: DefaultDict[Tuple[int, int], int] = defaultdict(lambda: 0)
for seg in segments:
for point in seg.points(diag=True):
points[point] += 1
# Figure out how many locations where at least 2 lines overlap
count = len([overlap for overlap in points.values() if overlap > 1])
print(f"{count} overlaps >1")
segments = [Seg.from_str(line) for line in sys.stdin]
print("Part 1")
part1(segments)
print("Part 2")
part2(segments)