Created
January 3, 2022 22:53
-
-
Save mlesniew/917eb629d6297865cd23ef92e0f2d5ce to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import itertools | |
import functools | |
import sys | |
AXIS_ORIENTATIONS = list(itertools.product([-1, 1], [-1, 1], [-1, 1])) | |
AXIS_ORDERS = list(itertools.permutations(range(3), 3)) | |
def shift_scanner(scanner, vector): | |
return tuple(tuple(c + d for c, d in zip(point, vector)) for point in scanner) | |
@functools.lru_cache(maxsize=None) | |
def get_mutants(scanner): | |
def iter_mutants(scanner): | |
for orientation in AXIS_ORIENTATIONS: | |
# apply axis negation | |
mutant = tuple( | |
tuple(c * o for c, o in zip(point, orientation)) for point in scanner | |
) | |
for order in AXIS_ORDERS: | |
yield tuple( | |
tuple(point[order[i]] for i in range(3)) for point in mutant | |
) | |
return list(iter_mutants(scanner)) | |
@functools.lru_cache(maxsize=None) | |
def align(target, original_scanner): | |
for scanner in get_mutants(original_scanner): | |
for target_point, scanner_point in itertools.product(target, scanner): | |
delta = tuple(target_point[i] - scanner_point[i] for i in range(3)) | |
shifted_scanner = shift_scanner(scanner, delta) | |
matches = len(set(shifted_scanner) & set(target)) | |
if matches >= 12: | |
# match! | |
return shifted_scanner, delta | |
# no match :( | |
return None, None | |
SCANNERS = [ | |
tuple( | |
tuple(int(x.strip()) for x in l.split(",")) | |
for l in s.split("\n") | |
if len(l.split(",")) == 3 | |
) | |
for s in sys.stdin.read().split("\n\n") | |
] | |
unaligned = list(SCANNERS) | |
initial = unaligned.pop() | |
aligned = [initial] | |
positions = {initial: (0, 0, 0)} | |
while unaligned: | |
for target, scanner in itertools.product(aligned, unaligned): | |
match, delta = align(target, scanner) | |
if match: | |
unaligned.remove(scanner) | |
aligned.append(match) | |
positions[match] = delta | |
break | |
else: | |
assert False, "No solution" | |
print("Part 1:", len(set(sum([list(scanner) for scanner in aligned], start=[])))) | |
print( | |
"Part 2:", | |
max( | |
sum(abs(c1 - c2) for c1, c2 in zip(sp1, sp2)) | |
for sp1, sp2 in itertools.product(positions.values(), positions.values()) | |
), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment