summaryrefslogtreecommitdiffstats
path: root/15.py
blob: f0f89047136e27052b8a140df4a147ef96adf0ee (plain)
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
from utils import open_day, Point2D, norm_1, inbounds
import re

regex = re.compile(r'^Sensor at x=(-?[0-9]+), y=(-?[0-9]+): closest beacon is at x=(-?[0-9]+), y=(-?[0-9]+)$')
sensors = []
with open_day(15) as f:
    for line in f:
        m = regex.match(line)
        assert(m)
        sx, sy, bx, by = map(int, m.group(1, 2, 3, 4))
        sensors.append((Point2D(sx, sy), Point2D(bx, by)))

def overlaps_at_y(sensors, y=2000000):
    beacons = sum(1 for b in set(b for _, b in sensors) if b.y == y)
    sensors = [s for s in ((s[0], norm_1(s[1] - s[0])) for s in sensors) if abs(s[0].y - y) <= s[1]]
    ranges = []
    for sensor, rang in sensors:
        dx = rang - abs(sensor.y - y)
        ranges.append((sensor.x - dx, sensor.x + dx))
    ranges.sort()
    count = 0
    cstart, cend = ranges.pop(0)
    for start, end in ranges:
        if start <= cend:
            cend = max(cend, end)
            continue
        count += cend - cstart + 1
        cstart, cend = start, end
    return count + cend - cstart + 1 - beacons

print(overlaps_at_y(sensors))

def edgepoints(sensors):
    for sp, bp in sensors:
        dist = norm_1(bp - sp) + 1
        for x in range(sp.x - dist, sp.x + dist + 1):
            dy = dist - abs(x - sp.x)
            yield Point2D(x, sp.y+dy)
            if dy != 0: yield Point2D(x, sp.y-dy)

def dedup(it):
    seen = set()
    for v in it:
        if v in seen: continue
        seen.add(v)
        yield v

def findbeacon(sensors, max_dim=4000000):
    for p in dedup(edgepoints(sensors)):
        if not inbounds(p, Point2D(max_dim + 1, max_dim + 1)): continue
        for sp, bp in sensors:
            dist = norm_1(bp - sp)
            if norm_1(p - sp) <= dist: break
        else:
            return p

def tuning_freq(p):
    return p.x * 4000000 + p.y
print(tuning_freq(findbeacon(sensors)))