summaryrefslogtreecommitdiffstats
path: root/11.py
blob: ae1b6a8dccb8c516cb3c44cfe94014efbd21f80e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# pyright: strict
from collections.abc import Callable, Iterable, Iterator
from dataclasses import dataclass
from itertools import accumulate, combinations, starmap
from sys import stdin
from typing import Self


@dataclass(frozen=True, slots=True)
class Point:
    x: int
    y: int

    def distance(self, other: Self) -> int:
        return abs(self.x - other.x) + abs(self.y - other.y)

    def __add__(self, other: Self) -> Self:
        return self.__class__(self.x + other.x, self.y + other.y)


def offsets(length: int, present: set[int]) -> list[int]:
    return list(accumulate(1 if i not in present else 0 for i in range(length)))


def dists(points: Iterable[Point]) -> Iterator[int]:
    return starmap(Point.distance, combinations(points, 2))


def offsetter(
    x_offsets: list[int], y_offsets: list[int], factor: int = 2
) -> Callable[[Point], Point]:
    scale = factor - 1

    def f(p: Point) -> Point:
        return p + Point(x_offsets[p.x] * scale, y_offsets[p.y] * scale)

    return f


points = {Point(x, y) for y, l in enumerate(stdin) for x, c in enumerate(l) if c == "#"}

x_present, y_present = set(p.x for p in points), set(p.y for p in points)
width, height = max(x for x in x_present) + 1, max(y for y in y_present) + 1
x_offsets = offsets(width, x_present)
y_offsets = offsets(height, y_present)

print(sum(dists(map(offsetter(x_offsets, y_offsets), points))))
print(sum(dists(map(offsetter(x_offsets, y_offsets, 1000000), points))))