2022 Day 15

This commit is contained in:
Akumatic 2022-12-15 17:06:33 +01:00
parent ebb668b56c
commit 14c4697ad0
7 changed files with 239 additions and 1 deletions

122
2022/15/README.md Normal file
View File

@ -0,0 +1,122 @@
# 2022 Day 15: Beacon Exclusion Zone
Copyright (c) Eric Wastl
#### [Direct Link](https://adventofcode.com/2022/day/15)
## Part 1
You feel the ground rumble again as the distress signal leads you to a large network of subterranean tunnels. You don't have time to search them all, but you don't need to: your pack contains a set of deployable **sensors** that you imagine were originally built to locate lost Elves.
The sensors aren't very powerful, but that's okay; your handheld device indicates that you're close enough to the source of the distress signal to use them. You pull the emergency sensor system out of your pack, hit the big button on top, and the sensors zoom off down the tunnels.
Once a sensor finds a spot it thinks will give it a good reading, it attaches itself to a hard surface and begins monitoring for the nearest signal source **beacon**. Sensors and beacons always exist at integer coordinates. Each sensor knows its own position and can **determine the position of a beacon precisely**; however, sensors can only lock on to the one beacon **closest to the sensor** as measured by the [Manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry). (There is never a tie where two beacons are the same distance to a sensor.)
It doesn't take long for the sensors to report back their positions and closest beacons (your puzzle input). For example:
```
Sensor at x=2, y=18: closest beacon is at x=-2, y=15
Sensor at x=9, y=16: closest beacon is at x=10, y=16
Sensor at x=13, y=2: closest beacon is at x=15, y=3
Sensor at x=12, y=14: closest beacon is at x=10, y=16
Sensor at x=10, y=20: closest beacon is at x=10, y=16
Sensor at x=14, y=17: closest beacon is at x=10, y=16
Sensor at x=8, y=7: closest beacon is at x=2, y=10
Sensor at x=2, y=0: closest beacon is at x=2, y=10
Sensor at x=0, y=11: closest beacon is at x=2, y=10
Sensor at x=20, y=14: closest beacon is at x=25, y=17
Sensor at x=17, y=20: closest beacon is at x=21, y=22
Sensor at x=16, y=7: closest beacon is at x=15, y=3
Sensor at x=14, y=3: closest beacon is at x=15, y=3
Sensor at x=20, y=1: closest beacon is at x=15, y=3
```
So, consider the sensor at `2,18`; the closest beacon to it is at `-2,15`. For the sensor at `9,16`, the closest beacon to it is at `10,16`.
Drawing sensors as `S` and beacons as `B`, the above arrangement of sensors and beacons looks like this:
```
1 1 2 2
0 5 0 5 0 5
0 ....S.......................
1 ......................S.....
2 ...............S............
3 ................SB..........
4 ............................
5 ............................
6 ............................
7 ..........S.......S.........
8 ............................
9 ............................
10 ....B.......................
11 ..S.........................
12 ............................
13 ............................
14 ..............S.......S.....
15 B...........................
16 ...........SB...............
17 ................S..........B
18 ....S.......................
19 ............................
20 ............S......S........
21 ............................
22 .......................B....
```
This isn't necessarily a comprehensive map of all beacons in the area, though. Because each sensor only identifies its closest beacon, if a sensor detects a beacon, you know there are no other beacons that close or closer to that sensor. There could still be beacons that just happen to not be the closest beacon to any sensor. Consider the sensor at `8,7`:
```
1 1 2 2
0 5 0 5 0 5
-2 ..........#.................
-1 .........###................
0 ....S...#####...............
1 .......#######........S.....
2 ......#########S............
3 .....###########SB..........
4 ....#############...........
5 ...###############..........
6 ..#################.........
7 .#########S#######S#........
8 ..#################.........
9 ...###############..........
10 ....B############...........
11 ..S..###########............
12 ......#########.............
13 .......#######..............
14 ........#####.S.......S.....
15 B........###................
16 ..........#SB...............
17 ................S..........B
18 ....S.......................
19 ............................
20 ............S......S........
21 ............................
22 .......................B....
```
This sensor's closest beacon is at `2,10`, and so you know there are no beacons that close or closer (in any positions marked `#`).
None of the detected beacons seem to be producing the distress signal, so you'll need to work out where the distress beacon is by working out where it **isn't**. For now, keep things simple by counting the positions where a beacon cannot possibly be along just a single row.
So, suppose you have an arrangement of beacons and sensors like in the example above and, just in the row where `y=10`, you'd like to count the number of positions a beacon cannot possibly exist. The coverage from all sensors near that row looks like this:
```
1 1 2 2
0 5 0 5 0 5
9 ...#########################...
10 ..####B######################..
11 .###S#############.###########.
```
In this example, in the row where `y=10`, there are **`26`** positions where a beacon cannot be present.
Consult the report from the sensors you just deployed. **In the row where `y=2000000`, how many positions cannot contain a beacon?**
## Part 2
Your handheld device indicates that the distress signal is coming from a beacon nearby. The distress beacon is not detected by any sensor, but the distress beacon must have `x` and `y` coordinates each no lower than `0` and no larger than `4000000`.
To isolate the distress beacon's signal, you need to determine its **tuning frequency**, which can be found by multiplying its `x` coordinate by `4000000` and then adding its `y` coordinate.
In the example above, the search space is smaller: instead, the `x` and `y` coordinates can each be at most `20`. With this reduced search area, there is only a single position that could have a beacon: `x=14, y=11`. The tuning frequency for this distress beacon is **`56000011`**.
Find the only possible position for the distress beacon. **What is its tuning frequency?**

51
2022/15/code.py Normal file
View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 Akumatic
#
# https://adventofcode.com/2022/day/15
from re import findall
def read_file(filename: str = "input.txt") -> list:
pattern = "Sensor at x=(.+), y=(.+): closest beacon is at x=(.+), y=(.*)"
with open(f"{__file__.rstrip('code.py')}{filename}", "r") as f:
return [[int(x) for x in findall(pattern, line)[0]] for line in f.readlines()]
def combine_ranges(ranges: list) -> list:
new_ranges = list()
start, stop = ranges[0]
for i in range(1, len(ranges)):
if ranges[i][0] > stop:
new_ranges.append(range(start, stop))
start, stop = ranges[i]
continue
if ranges[i][1] > stop:
stop = ranges[i][1]
new_ranges.append(range(start, stop))
return new_ranges
def get_blocked_ranges(coords: list, line: int, _min = float('-inf'), _max = float('inf')) -> list:
ranges = list()
for sx, sy, bx, by in coords:
sb_dist = abs(bx - sx) + abs(by - sy)
height_dist = abs(sy - line)
if height_dist > sb_dist:
continue
x_min = max(sx - (sb_dist - height_dist), _min)
x_max = min(sx + (sb_dist - height_dist), _max)
ranges.append((x_min, x_max))
return combine_ranges(sorted(ranges))
def part1(vals: list, test: bool = False) -> int:
return sum(len(r) for r in get_blocked_ranges(vals, 10 if test else 2000000))
def part2(vals: list, test: bool = False) -> int:
max_val = 20 if test else 4000000
for i in range(max_val + 1):
ranges = get_blocked_ranges(vals, i, 0, max_val)
if len(ranges) > 1:
return (ranges[0].stop + 1) * 4000000 + i
if __name__ == "__main__":
vals = read_file()
print(f"Part 1: {part1(vals)}")
print(f"Part 2: {part2(vals)}")

35
2022/15/input.txt Normal file
View File

@ -0,0 +1,35 @@
Sensor at x=2150774, y=3136587: closest beacon is at x=2561642, y=2914773
Sensor at x=3983829, y=2469869: closest beacon is at x=3665790, y=2180751
Sensor at x=2237598, y=3361: closest beacon is at x=1780972, y=230594
Sensor at x=1872170, y=78941: closest beacon is at x=1780972, y=230594
Sensor at x=3444410, y=3965835: closest beacon is at x=3516124, y=3802509
Sensor at x=3231566, y=690357: closest beacon is at x=2765025, y=1851710
Sensor at x=3277640, y=2292194: closest beacon is at x=3665790, y=2180751
Sensor at x=135769, y=50772: closest beacon is at x=1780972, y=230594
Sensor at x=29576, y=1865177: closest beacon is at x=255250, y=2000000
Sensor at x=3567617, y=3020368: closest beacon is at x=3516124, y=3802509
Sensor at x=1774477, y=148095: closest beacon is at x=1780972, y=230594
Sensor at x=1807041, y=359900: closest beacon is at x=1780972, y=230594
Sensor at x=1699781, y=420687: closest beacon is at x=1780972, y=230594
Sensor at x=2867703, y=3669544: closest beacon is at x=3516124, y=3802509
Sensor at x=1448060, y=201395: closest beacon is at x=1780972, y=230594
Sensor at x=3692914, y=3987880: closest beacon is at x=3516124, y=3802509
Sensor at x=3536880, y=3916422: closest beacon is at x=3516124, y=3802509
Sensor at x=2348489, y=2489095: closest beacon is at x=2561642, y=2914773
Sensor at x=990761, y=2771300: closest beacon is at x=255250, y=2000000
Sensor at x=1608040, y=280476: closest beacon is at x=1780972, y=230594
Sensor at x=2206669, y=1386195: closest beacon is at x=2765025, y=1851710
Sensor at x=3932320, y=3765626: closest beacon is at x=3516124, y=3802509
Sensor at x=777553, y=1030378: closest beacon is at x=255250, y=2000000
Sensor at x=1844904, y=279512: closest beacon is at x=1780972, y=230594
Sensor at x=2003315, y=204713: closest beacon is at x=1780972, y=230594
Sensor at x=2858315, y=2327227: closest beacon is at x=2765025, y=1851710
Sensor at x=3924483, y=1797070: closest beacon is at x=3665790, y=2180751
Sensor at x=1572227, y=3984898: closest beacon is at x=1566446, y=4774401
Sensor at x=1511706, y=1797308: closest beacon is at x=2765025, y=1851710
Sensor at x=79663, y=2162372: closest beacon is at x=255250, y=2000000
Sensor at x=3791701, y=2077777: closest beacon is at x=3665790, y=2180751
Sensor at x=2172093, y=3779847: closest beacon is at x=2561642, y=2914773
Sensor at x=2950352, y=2883992: closest beacon is at x=2561642, y=2914773
Sensor at x=3629602, y=3854760: closest beacon is at x=3516124, y=3802509
Sensor at x=474030, y=3469506: closest beacon is at x=-452614, y=3558516

2
2022/15/solution.txt Normal file
View File

@ -0,0 +1,2 @@
Part 1: 4560025
Part 2: 12480406634249

14
2022/15/test_code.py Normal file
View File

@ -0,0 +1,14 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 Akumatic
from code import read_file, part1, part2
def test():
vals = read_file("test_input.txt")
assert part1(vals, test=True) == 26
print("Passed Part 1")
assert part2(vals, test=True) == 56000011
print("Passed Part 2")
if __name__ == "__main__":
test()

14
2022/15/test_input.txt Normal file
View File

@ -0,0 +1,14 @@
Sensor at x=2, y=18: closest beacon is at x=-2, y=15
Sensor at x=9, y=16: closest beacon is at x=10, y=16
Sensor at x=13, y=2: closest beacon is at x=15, y=3
Sensor at x=12, y=14: closest beacon is at x=10, y=16
Sensor at x=10, y=20: closest beacon is at x=10, y=16
Sensor at x=14, y=17: closest beacon is at x=10, y=16
Sensor at x=8, y=7: closest beacon is at x=2, y=10
Sensor at x=2, y=0: closest beacon is at x=2, y=10
Sensor at x=0, y=11: closest beacon is at x=2, y=10
Sensor at x=20, y=14: closest beacon is at x=25, y=17
Sensor at x=17, y=20: closest beacon is at x=21, y=22
Sensor at x=16, y=7: closest beacon is at x=15, y=3
Sensor at x=14, y=3: closest beacon is at x=15, y=3
Sensor at x=20, y=1: closest beacon is at x=15, y=3

View File

@ -29,7 +29,7 @@ Collect stars by solving puzzles. Two puzzles will be made available on each day
| 12 | :white_check_mark: | :white_check_mark: | [Solution](12/code.py) | [Day 12](https://adventofcode.com/2022/day/12) |
| 13 | :white_check_mark: | :white_check_mark: | [Solution](13/code.py) | [Day 13](https://adventofcode.com/2022/day/13) |
| 14 | :white_check_mark: | :white_check_mark: | [Solution](14/code.py) | [Day 14](https://adventofcode.com/2022/day/14) |
| 15 | | | | [Day 15](https://adventofcode.com/2022/day/15) |
| 15 | :white_check_mark: | :white_check_mark: | [Solution](15/code.py) | [Day 15](https://adventofcode.com/2022/day/15) |
| 16 | | | | [Day 16](https://adventofcode.com/2022/day/16) |
| 17 | | | | [Day 17](https://adventofcode.com/2022/day/17) |
| 18 | | | | [Day 18](https://adventofcode.com/2022/day/18) |