#!/usr/bin/python3 import fileinput import re targety = 2000000 sensors = [] beacons = set() beacons_on_target_y = 0 r = r'Sensor at x=(-?\d+), y=(-?\d+).*beacon is at x=(-?\d+), y=(-?\d+)' for line in fileinput.input(): result = re.search(r, line) sx, sy, bx, by = list(map(int, result.groups())) dist = abs(bx-sx) + abs(by-sy) sensors.append((sx,sy,dist)) beacons.add((bx,by)) for b in beacons: if b[1] == targety: beacons_on_target_y += 1 # Project each sensor's coverage diamond onto the target row. # Number of cells covered is either 0, or an odd number (1, 3, 5, ...). # # .................#..... # ................###.... <= target row # ........#......#####... # ..#....###....#######.. # .#S#..##S##..####S####. # ..#....###....#######.. # ........#......#####... # ................###.... # .................#..... # # With the sensor 3 units away vertically, range 1 or 2 provides no coverage. # Range 3 (= dY) provides 1 unit of coverage at sensor's X. # Range dY+1 provides 3 units of coverage, SX-1 to SX+1. # Range dY+n provides 2n+1 coverage, from SX-n to SX+n. coverage = [] for s in sensors: sx, sy, srange = s dist = abs(sy - targety) if dist > srange: continue coverage.append((sx-(srange-dist),sx+(srange-dist))) # print(coverage) # Remove redundant coverage elements. # Use stuff from day 4 part 1. redundant = [False] * len(coverage) for i in range(0, len(coverage)-1): for j in range(i+1, len(coverage)): if i == j: continue a, b = coverage[i] c, d = coverage[j] considered = j if (a > c) or (a == c and d > b): a, b, c, d = c, d, a, b considered = i if a <= c and b >= d: redundant[considered] = True # print(redundant) newlist = [] for i in range(0, len(coverage)): if not redundant[i]: newlist.append(coverage[i]) coverage = newlist # print(coverage) # Now see how many tiles of the target Y are covered. # Start by finding the lowest and highest covered tiles. xmin, xmax = coverage[0] for c in coverage: if c[0] < xmin: xmin = c[0] if c[1] > xmax: xmax = c[1] total = 0 for x in range(xmin, xmax+1): for c in coverage: if x >= c[0] and x <= c[1]: total += 1 break print(total - beacons_on_target_y)