Add day 19 solution
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2021-12-19 17:40:51 +01:00
parent ca9e753968
commit a7363a8fa3
3 changed files with 1559 additions and 0 deletions

165
day-19/day-19.py Normal file
View File

@@ -0,0 +1,165 @@
#!/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):
b = tuple([int(x) for x in line.split(',')])
s.append(b)
else:
scanners.append(s)
if len(s):
scanners.append(s)
return scanners
def calc_distances(s):
d = []
for _ in s:
d.append(set())
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 in range(len(scanners[n]['beacons'])):
(x, y, z) = scanners[n]['beacons'][i]
scanners[n]['beacons'][i] = eval(transform_func)
(xo, yo, zo) = scanners[idx]['origin']
(x0, y0, z0) = scanners[idx]['beacons'][overlapping[0][0]]
(x1, y1, z1) = scanners[n]['beacons'][overlapping[0][1]]
scanners[n]['origin'] = (xo + x0 - x1, yo + y0 - y1, zo + z0 - z1)
(xo, yo, zo) = scanners[n]['origin']
transform(scanners, n, done)
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)
def solve(input):
result_p1 = 0
result_p2 = 0
beacons = parse(input)
scanners = []
for b in beacons:
s = {}
s['beacons'] = b
s['metrics'] = calc_distances(b)
s['origin'] = (0, 0, 0)
s['overlapping'] = []
scanners.append(s)
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'].append(j)
scanners[j]['overlapping'].append(i)
transform(scanners, 0)
m = set()
for s in scanners:
for b in s['beacons']:
m.add(b)
result_p1 = len(m)
for i in range(len(scanners)):
(xi, yi, zi) = scanners[i]['origin']
for j in range(i + 1, len(scanners)):
(xj, yj, zj) = scanners[j]['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)