-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbeacon_exclusion_zone.py
78 lines (51 loc) · 1.87 KB
/
beacon_exclusion_zone.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
from utils import read_input, run
from collections import Counter
FNAME = "15/input.txt"
def parse_line(line):
return [tuple(int(coord.rstrip(',')[2:]) for coord in item.split(' ')[-2:]) for item in line.split(':')]
##########
# PART 1 #
##########
def distance(c1, c2):
x1, y1 = c1
x2, y2 = c2
return abs(x2 - x1) + abs(y2 - y1)
def find_not_possible(data, target_y):
not_possible = set()
for sensor, beacon in data:
x, y = sensor
dist = distance(sensor, beacon)
remaining_dist = dist - abs(target_y - y)
if remaining_dist >= 0:
not_possible |= {x + i for i in range(-remaining_dist, remaining_dist)}
return not_possible
def part_one(input_file):
data = read_input(input_file, parse_chunk=parse_line)
return len(find_not_possible(data, 2_000_000))
##########
# PART 2 #
##########
def is_correct(data, coord):
return all(distance(sensor, coord) > distance(sensor, beacon) for sensor, beacon in data)
def find_outer_coords(counter: Counter, sensor, beacon):
dist = distance(sensor, beacon) + 1
x, y = sensor
# Possible optimisation: just store the lines for each square
# only consider points that intersect
for i in range(dist):
for edge_x in (x + dist - i, x - dist + i):
for edge_y in (y-i, y+i):
if 0 <= edge_x <= 4_000_000 and 0 <= edge_y <= 4_000_000:
counter[(edge_x, edge_y)] += 1
return counter
def part_two(input_file):
data = read_input(input_file, parse_chunk=parse_line)
counts = Counter()
for sensor, beacon in data:
find_outer_coords(counts, sensor, beacon)
if answer := next((p for p in counts if counts[p] >= 4 and is_correct(data, p)), None):
x, y = answer
return x * 4_000_000 + y
return None
if __name__ == '__main__':
run(part_one, part_two, FNAME)