Files
advent-of-code-2021/day-19/day-19.py
Pascal Lais 7def74b81e
All checks were successful
continuous-integration/drone/push Build is passing
Update day 19 solution
2021-12-19 21:54:46 +01:00

161 lines
4.6 KiB
Python

#!/usr/bin/env python3
from pathlib import Path
def parse(input):
scanners = []
s = []
for line in input:
line = line.rstrip()
if 'scanner' in line:
s = []
continue
if len(line):
s.append(tuple([int(x) for x in line.split(',')]))
else:
scanners.append(s)
if len(s):
scanners.append(s)
return scanners
def calc_distances(s):
d = [set() for _ in s]
for i in range(len(s)):
for j in range(i+1, len(s)):
dist = 0
for k in range(len(s[i])):
dist += (s[i][k] - s[j][k]) ** 2
d[i].add(dist)
d[j].add(dist)
return d
def num_overlapping(s0, s1):
num = 0
for b0 in s0:
for b1 in s1:
if 11 <= len(b0 & b1):
num += 1
return num
def get_transform_func(v0, v1):
(x0, y0, z0) = v0
(x1, y1, z1) = v1
transform = '('
if abs(x0) == abs(x1):
if 0 > x0 // x1:
transform += '-'
transform += 'x,'
elif abs(x0) == abs(y1):
if 0 > x0 // y1:
transform += '-'
transform += 'y,'
elif abs(x0) == abs(z1):
if 0 > x0 // z1:
transform += '-'
transform += 'z,'
if abs(y0) == abs(x1):
if 0 > y0 // x1:
transform += '-'
transform += 'x,'
elif abs(y0) == abs(y1):
if 0 > y0 // y1:
transform += '-'
transform += 'y,'
elif abs(y0) == abs(z1):
if 0 > y0 // z1:
transform += '-'
transform += 'z,'
if abs(z0) == abs(x1):
if 0 > z0 // x1:
transform += '-'
transform += 'x'
elif abs(z0) == abs(y1):
if 0 > z0 // y1:
transform += '-'
transform += 'y'
elif abs(z0) == abs(z1):
if 0 > z0 // z1:
transform += '-'
transform += 'z'
transform += ')'
return transform
def transform(scanners, idx, done=[]):
done.append(idx)
for n in scanners[idx]['overlapping']:
if n in done:
continue
overlapping = []
for i, b0 in enumerate(scanners[idx]['metrics']):
for j, b1 in enumerate(scanners[n]['metrics']):
if 11 <= len(b0 & b1):
overlapping.append((i, j))
if 2 <= len(overlapping):
break
if 2 <= len(overlapping):
break
assert len(overlapping) == 2
(x0, y0, z0) = scanners[idx]['beacons'][overlapping[0][0]]
(x1, y1, z1) = scanners[idx]['beacons'][overlapping[1][0]]
v0 = (x0 - x1, y0 - y1, z0 - z1)
(x0, y0, z0) = scanners[n]['beacons'][overlapping[0][1]]
(x1, y1, z1) = scanners[n]['beacons'][overlapping[1][1]]
v1 = (x0 - x1, y0 - y1, z0 - z1)
transform_func = get_transform_func(v0, v1)
for i, b in enumerate(scanners[n]['beacons']):
(x, y, z) = b
scanners[n]['beacons'][i] = eval(transform_func)
(x0, y0, z0) = scanners[idx]['beacons'][overlapping[0][0]]
(x1, y1, z1) = scanners[n]['beacons'][overlapping[0][1]]
(xo, yo, zo) = (x0 - x1, y0 - y1, z0 - z1)
scanners[n]['origin'] = (xo, yo, zo)
for i in range(len(scanners[n]['beacons'])):
(x, y, z) = scanners[n]['beacons'][i]
scanners[n]['beacons'][i] = (x + xo, y + yo, z + zo)
transform(scanners, n, done)
def solve(input):
result_p1 = 0
result_p2 = 0
beacons = parse(input)
scanners = []
for b in beacons:
scanners.append({
'beacons': b,
'metrics': calc_distances(b),
'origin': (0, 0, 0),
'overlapping': set()})
for i in range(len(scanners)):
for j in range(i + 1, len(scanners)):
num = num_overlapping(
scanners[i]['metrics'], scanners[j]['metrics'])
if num:
scanners[i]['overlapping'].add(j)
scanners[j]['overlapping'].add(i)
transform(scanners, 0)
m = set()
for s in scanners:
for b in s['beacons']:
m.add(b)
result_p1 = len(m)
for i, si in enumerate(scanners):
(xi, yi, zi) = si['origin']
for j, sj in enumerate(scanners[i + 1:]):
(xj, yj, zj) = sj['origin']
md = abs(xi - xj) + abs(yi - yj) + abs(zi - zj)
result_p2 = max(result_p2, md)
print("Part 1 result:", result_p1)
print("Part 2 result:", result_p2)
input = list()
p = Path(__file__).with_name('input.txt')
with open(p) as f:
input = f.readlines()
solve(input)