From 0b715584879ddea7d72a6b033faf8fa43595aa2e Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Mon, 11 Dec 2023 15:17:00 +0000 Subject: day 11 more functional --- 11.py | 52 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/11.py b/11.py index 645c6c7..ae1b6a8 100644 --- a/11.py +++ b/11.py @@ -1,38 +1,48 @@ # pyright: strict -from itertools import accumulate, combinations +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 solve( - points: set[tuple[int, int]], - x_offsets: list[int], - y_offsets: list[int], - expansion: int = 2, -) -> int: - def offset(p: tuple[int, int]) -> tuple[int, int]: - return ( - p[0] + x_offsets[p[0]] * (expansion - 1), - p[1] + y_offsets[p[1]] * (expansion - 1), - ) +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 manhattan_distance(a: tuple[int, int], b: tuple[int, int]) -> int: - return abs(a[0] - b[0]) + abs(a[1] - b[1]) + def f(p: Point) -> Point: + return p + Point(x_offsets[p.x] * scale, y_offsets[p.y] * scale) - return sum( - manhattan_distance(offset(a), offset(b)) for a, b in combinations(points, 2) - ) + return f -points = {(x, y) for y, l in enumerate(stdin) for x, c in enumerate(l) if c == "#"} +points = {Point(x, y) for y, l in enumerate(stdin) for x, c in enumerate(l) if c == "#"} -x_present, y_present = set(p[0] for p in points), set(p[1] for p in points) +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(solve(points, x_offsets, y_offsets)) -print(solve(points, x_offsets, y_offsets, 1000000)) +print(sum(dists(map(offsetter(x_offsets, y_offsets), points)))) +print(sum(dists(map(offsetter(x_offsets, y_offsets, 1000000), points)))) -- cgit v1.2.3-54-g00ecf