| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- #!/usr/bin/env python3
- import sys
- from itertools import combinations, starmap
- from collections import deque, Counter
- def parse(f):
- for line in f:
- if line.startswith('---'):
- scan = []
- elif line == '\n':
- yield scan
- else:
- scan.append(tuple(map(int, line.split(','))))
- yield scan
- def rotx(x, y, z):
- return x, -z, y
- def rotz(x, y, z):
- return -y, x, z
- ALL_ROTATIONS = (
- rotz, rotz, rotz,
- rotx,
- rotz, rotz, rotz,
- rotx,
- rotz, rotz, rotz,
- lambda x, y, z: (-x, -z, -y),
- rotz, rotz, rotz,
- rotx,
- rotz, rotz, rotz,
- lambda x, y, z: (x, z, -y),
- rotz, rotz, rotz,
- )
- def rotations(scan):
- yield scan
- for rot in ALL_ROTATIONS:
- scan = list(starmap(rot, scan))
- yield scan
- def move(scan, dx, dy, dz):
- return [(x + dx, y + dy, z + dz) for x, y, z in scan]
- def find_scanner(base, rotated_scans):
- for scan in rotated_scans:
- [(diff, count)] = Counter((x2 - x1, y2 - y1, z2 - z1)
- for x1, y1, z1 in scan
- for x2, y2, z2 in base).most_common(1)
- if count >= 12:
- return diff, move(scan, *diff)
- return None, None
- def join(scans):
- joined = set(next(scans))
- remaining = deque(list(rotations(scan)) for scan in scans)
- scanners = [(0, 0, 0)]
- while remaining:
- rotated_scans = remaining.popleft()
- scanner, moved = find_scanner(joined, rotated_scans)
- if scanner:
- joined |= set(moved)
- scanners.append(scanner)
- else:
- remaining.append(rotated_scans)
- return joined, scanners
- def max_distance(scanners):
- return max(abs(x2 - x1) + abs(y2 - y1) + abs(z2 - z1)
- for (x1, y1, z1), (x2, y2, z2) in combinations(scanners, 2))
- joined, scanners = join(parse(sys.stdin))
- print(len(joined))
- print(max_distance(scanners))
|