from functools import reduce from math import prod, sqrt from pathlib import Path from typing import TypeAlias Point: TypeAlias = tuple[int, int, int] FILE = "input.txt" class Circuit: def __init__(self, points: set[Point]) -> None: self.points: set[Point] = points def __contains__(self, other: Circuit) -> bool: for p in other.points: if p in self.points: return True return False def merge(self, other: Circuit) -> Circuit: return Circuit(self.points.union(other.points)) def main(): lines = Path(FILE).read_text().splitlines() points: list[Point] = [parse_point(line) for line in lines] distances = sorted([ (distance(p1, p2), Circuit({p1, p2})) for i, p1 in enumerate(points) for p2 in points[i+1:] ], key=lambda x: x[0]) big_circuits: list[Circuit] = [] for (_, small_circuit) in distances[:1000]: new_circuits: list[Circuit] = [] for big_circuit in big_circuits: if small_circuit in big_circuit: new_circuits.append(big_circuit) if len(new_circuits): for circuit in new_circuits: big_circuits.remove(circuit) new_circuits.append(small_circuit) new_circuit = reduce(lambda a, b: a.merge(b), new_circuits) big_circuits.append(new_circuit) else: big_circuits.append(small_circuit) circuits = sorted( big_circuits, key=lambda x: len(x.points), reverse=True ) return prod(len(c.points) for c in circuits[:3]) def distance(p1: tuple[int, int, int], p2: tuple[int, int, int]): x1, y1, z1 = p1 x2, y2, z2 = p2 return sqrt((x2-x1)**2+(y2-y1)**2+(z2-z1)**2) def parse_point(line: str) -> Point: x, y, z = line.split(",") return (int(x), int(y), int(z)) if __name__ == "__main__": print(main())