2021-12-05 13:38:14 +01:00
|
|
|
import re
|
|
|
|
from itertools import repeat
|
|
|
|
from typing import Iterable, Tuple
|
|
|
|
|
|
|
|
|
|
|
|
pattern = re.compile(r'(\d+),(\d+) -> (\d+),(\d+)')
|
|
|
|
|
|
|
|
|
|
|
|
def loader() -> list[Tuple[Tuple[int, int], Tuple[int, int]]]:
|
|
|
|
with open('../.input/day05', 'r') as f:
|
|
|
|
return [
|
|
|
|
((int(x1), int(y1)), (int(x2), int(y2)))
|
|
|
|
for x1, y1, x2, y2
|
|
|
|
in pattern.findall(f.read())
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def find_points_in_line(x1, y1, x2, y2, skip_diagonal: bool = False) -> Iterable[Tuple[int, int]]:
|
|
|
|
if skip_diagonal and x1 != x2 and y1 != y2:
|
|
|
|
return []
|
|
|
|
if x2 < x1 and y2 < y1:
|
|
|
|
return find_points_in_line(x2, y2, x1, y1)
|
|
|
|
if x2 < x1:
|
|
|
|
y = (y for y in range(y1, y2 + 1)) if y1 != y2 else repeat(y1)
|
|
|
|
return zip(range(x1, x2 - 1, -1), y)
|
|
|
|
if y2 < y1:
|
|
|
|
x = (x for x in range(x1, x2 + 1)) if x1 != x2 else repeat(x1)
|
|
|
|
return zip(x, range(y1, y2 - 1, -1))
|
|
|
|
if x1 == x2:
|
|
|
|
return zip(repeat(x1), range(min(y1, y2), max(y1, y2) + 1))
|
|
|
|
if y1 == y2:
|
|
|
|
return zip(range(min(x1, x2), max(x1, x2) + 1), repeat(y1))
|
|
|
|
return zip(range(x1, x2 + 1), range(y1, y2 + 1))
|
|
|
|
|
|
|
|
|
2021-12-05 13:40:39 +01:00
|
|
|
def solve1(skip_diagonal=True) -> int:
|
2021-12-05 13:38:14 +01:00
|
|
|
visited_pts = set()
|
|
|
|
crossed_pts = set()
|
|
|
|
for (start, end) in loader():
|
2021-12-05 13:40:39 +01:00
|
|
|
for x, y in find_points_in_line(*start, *end, skip_diagonal):
|
2021-12-05 13:38:14 +01:00
|
|
|
if (x, y) in visited_pts:
|
|
|
|
crossed_pts.add((x, y))
|
|
|
|
else:
|
|
|
|
visited_pts.add((x, y))
|
|
|
|
return len(crossed_pts)
|
2021-12-05 13:40:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
def solve2() -> int:
|
|
|
|
return solve1(skip_diagonal=False)
|
2021-12-05 13:38:14 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2021-12-05 13:40:39 +01:00
|
|
|
print(solve1()) # 5690
|
|
|
|
print(solve2()) # 17741
|