-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathday15.py
executable file
·83 lines (63 loc) · 1.9 KB
/
day15.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/usr/bin/env python3
import re
from itertools import starmap, combinations
import sys
def manhattan(ax, ay, bx, by):
return abs(ax - bx) + abs(ay - by)
def diamond_segment(sx, sy, r):
dist = abs(2000000 - sy)
if dist <= r:
return (sx - r + dist, sx + r - dist)
def invalid_spots(sensors):
segments = iter(sorted(filter(None, starmap(diamond_segment, sensors))))
start, end = next(segments)
total = 0
for s, e in segments:
if s > end + 1:
total += end - start + 1
start, end = s, e
else:
end = max(end, e)
return total + end - start + 1
def sides(sx, sy, r):
r += 1
yield -sx + sy + r # a/\b a: y = x - sx + sy + r + 1
yield sx + sy + r # / \ b: y = -x + sx + sy + r + 1
yield -sx + sy - r # \ / c: y = x - sx + sy - r - 1
yield sx + sy - r # d\/c d: y = -x + sx + sy - r - 1
def intersect(a, b):
x = (b - a) // 2
return x, x + a
def candidates(s1, s2):
a1, b1, c1, d1 = sides(*s1)
a2, b2, c2, d2 = sides(*s2)
yield intersect(a1, b2)
yield intersect(a1, d2)
yield intersect(c1, b2)
yield intersect(c1, d2)
yield intersect(a2, b1)
yield intersect(a2, d1)
yield intersect(c2, b1)
yield intersect(c2, d1)
def missing_beacon(sensors):
for s1, s2 in combinations(sensors, 2):
for x, y in candidates(s1, s2):
if x < 0 or x > 4000000 or y < 0 or y > 4000000:
continue
if all(manhattan(sx, sy, x, y) > r for sx, sy, r in sensors):
return x, y
# Open the first argument as input or use stdin if no arguments were given
fin = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
exp = re.compile(r'-?\d+')
sensors = []
beacons_on_target = set()
for line in fin:
sx, sy, bx, by = map(int, exp.findall(line))
sensors.append((sx, sy, manhattan(sx, sy, bx, by)))
if by == 2000000:
beacons_on_target.add(bx)
answer = invalid_spots(sensors) - len(beacons_on_target)
print('Part 1:', answer)
x, y = missing_beacon(sensors)
answer = x * 4000000 + y
print('Part 2:', answer)