You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
2.4 KiB

3 years ago
from itertools import combinations
def readInput(fileName):
scanners = []
with open(fileName) as file:
lines = file.read().splitlines()
for line in lines:
if line == "":
continue
if line.startswith("---"):
scanners.append(set())
continue
scanners[len(scanners) - 1].add(tuple(int(value) for value in line.split(",")))
return scanners
Point = tuple[int, int, int]
axes = {(1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1)}
def transform(p: Point, up: Point, rotation: int):
new = {
(1, 0, 0): (p[1], p[0], -p[2]),
(-1, 0, 0): (p[1], -p[0], p[2]),
(0, 1, 0): p,
(0, -1, 0): (p[0], -p[1], -p[2]),
(0, 0, 1): (p[1], p[2], p[0]),
(0, 0, -1): (p[1], -p[2], -p[0])
}[up]
return {
0: new,
1: (new[2], new[1], -new[0]),
2: (-new[0], new[1], -new[2]),
3: (-new[2], new[1], new[0])
}[rotation]
def add(p1: Point, p2: Point):
return tuple(val1 + val2 for val1, val2 in zip(p1, p2))
def sub(p1: Point, p2: Point):
return tuple(val1 - val2 for val1, val2 in zip(p1, p2))
def align(beacons1: set[Point], beacons2: set[Point]):
for axis in axes:
for rotation in range(4):
rotatedBeacons2 = set(transform(p, axis, rotation) for p in beacons2)
for b1 in beacons1:
for maybeMatchingInB2 in rotatedBeacons2:
delta = sub(b1, maybeMatchingInB2)
transformedBeacons2 = set(add(p, delta) for p in rotatedBeacons2)
if len(transformedBeacons2.intersection(beacons1)) >= 12:
return transformedBeacons2, delta, axis, rotation
return None
def reduce(scans: list[set[Point]], scanners: list[set[Point]]):
toRemove = set()
for i in range(len(scans) - 1):
for j in range(i + 1, len(scans)):
if j in toRemove:
continue
alignment = align(scans[i], scans[j])
if alignment is not None:
alignedBeacons, translation, up, rotation = alignment
for scan in scanners[j]:
scanners[i].add(add(translation, transform(scan, up, rotation)))
scans[i] |= alignedBeacons
toRemove.add(j)
return [s for i, s in enumerate(scans) if i not in toRemove], [s for i, s in enumerate(scanners) if i not in toRemove]
def solve():
scans = readInput("input")
scanners = [{(0, 0, 0)} for _ in scans]
while len(scans) > 1:
scans, scanners = reduce(scans, scanners)
allBeacons = scans[0]
print(len(allBeacons))
print(max(abs(x1 - x2) + abs(y1 - y2) + abs(z1 - z2) for (x1, y1, z1), (x2, y2, z2) in combinations(scanners[0], 2)))
solve()