From f777d1a3b41d02d19c833b5cd099d25a5d4867e3 Mon Sep 17 00:00:00 2001 From: dece Date: Thu, 23 Dec 2021 00:44:16 +0100 Subject: [PATCH] Day 19, sloooow --- 2021/day19.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 2021/day19.py diff --git a/2021/day19.py b/2021/day19.py new file mode 100644 index 0000000..5694560 --- /dev/null +++ b/2021/day19.py @@ -0,0 +1,97 @@ +from collections import defaultdict +from itertools import combinations, permutations + +with open("input19.txt") as f: + lines = [line.rstrip() for line in f] +scanners = [] +for line in lines: + if line.startswith("--"): + scanner_id = int(line.split()[2]) + positions = [] + elif line: + positions.append(tuple(map(int, line.split(",")))) + else: + scanners.append((scanner_id, positions)) +scanners.append((scanner_id, positions)) + + +def N(x, y, z): return x, y, z +def X(x, y, z): return x, -z, y +def Y(x, y, z): return -z, y, x +def add(v1, v2): return v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2] +def sub(v1, v2): return v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2] + + +orientations = [ + "N", "X", "Y", "XX", "XY", "YX", "YY", "XXX", "XXY", "XYX", "XYY", "YXX", + "YYX", "YYY", "XXXY", "XXYX", "XXYY", "XYXX", "XYYY", "YXXX", "YYYX", + "XXXYX", "XYXXX", "XYYYX" +] +rotations = {k: globals()[k] for k in "NXY"} + + +def orient(x, y, z, orientation): + for axis in orientation: + x, y, z = rotations[axis[::-1]](x, y, z) + return x, y, z + + +overlaps = {} +oriented = { + sb_id: [(o, [orient(*pos, o) for pos in sb]) for o in orientations] + for sb_id, sb in scanners +} +# Using permutations is slower than combinations but it's simpler to find the +# transform path after. +for (sa_id, sa), (sb_id, _) in permutations(scanners, 2): + for orientation, osb in oriented[sb_id]: + diffs = defaultdict(int) + for ax, ay, az in sa: + for bx, by, bz in osb: + diff = (ax - bx, ay - by, az - bz) + diffs[diff] += 1 + if diffs[diff] >= 12: + overlaps[(sa_id, sb_id)] = (orientation, diff) + break + else: + continue + break + else: + continue + break + + +def find_transform_to_0(from_s): + chains = [[p] for p in overlaps if p[0] == from_s] + seen = set() + while chains: + chain = chains.pop(0) + if chain[-1][1] == 0: + return chain + for p in overlaps: + if p[0] == chain[-1][1] and p not in seen: + seen.add(p) + chains.append(chain + [p]) + + +def see_as_0(x, y, z, sid): + for t in find_transform_to_0(sid): + ori, move = overlaps[t[::-1]] + x, y, z = add(orient(x, y, z, ori), move) + return x, y, z + + +def see_scanner_as_0(sid, sdata): + for x, y, z in sdata: + yield see_as_0(x, y, z, sid) + + +beacons = set() +for scanner_id in range(len(scanners)): + beacons |= set(list(see_scanner_as_0(*scanners[scanner_id]))) +print(len(beacons)) +scanner_positions = [see_as_0(0, 0, 0, sid) for sid in range(len(scanners))] +print(max( + sum(map(abs, sub(spb, spa))) + for spa, spb in combinations(scanner_positions, 2) +))