diff options
| -rw-r--r-- | day15/__init__.py | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/day15/__init__.py b/day15/__init__.py index b43cae1..c22f0c1 100644 --- a/day15/__init__.py +++ b/day15/__init__.py | |||
| @@ -3,20 +3,21 @@ import re | |||
| 3 | from abc import ABC | 3 | from abc import ABC |
| 4 | from collections import namedtuple | 4 | from collections import namedtuple |
| 5 | from dataclasses import dataclass, field | 5 | from dataclasses import dataclass, field |
| 6 | from typing import Tuple, Iterator, Any, Set | 6 | from typing import Tuple, Iterator, Any, Set, Union |
| 7 | 7 | ||
| 8 | from aoc import BaseAssignment | 8 | from aoc import BaseAssignment |
| 9 | 9 | ||
| 10 | 10 | ||
| 11 | class Coordinate(namedtuple("Coordinate", ["x", "y"])): | 11 | class Coordinate(namedtuple("Coordinate", ["x", "y"])): |
| 12 | def distance(self, other: "Coordinate"): | 12 | def distance(self, other: "Coordinate"): |
| 13 | return abs(other.x - self.x) + abs(other.y - self.y) | 13 | return abs(self.x - other.x) + abs(self.y - other.y) |
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | @dataclass | 16 | @dataclass |
| 17 | class Sensor: | 17 | class Sensor: |
| 18 | coordinate: Coordinate | 18 | coordinate: Coordinate |
| 19 | nearest: Coordinate | 19 | nearest: Coordinate |
| 20 | radius: int = None | ||
| 20 | 21 | ||
| 21 | def __hash__(self): | 22 | def __hash__(self): |
| 22 | return hash(self.coordinate) | 23 | return hash(self.coordinate) |
| @@ -24,6 +25,25 @@ class Sensor: | |||
| 24 | def __post_init__(self): | 25 | def __post_init__(self): |
| 25 | self.radius = self.coordinate.distance(self.nearest) | 26 | self.radius = self.coordinate.distance(self.nearest) |
| 26 | 27 | ||
| 28 | def within_radius(self, coordinate: Coordinate) -> bool: | ||
| 29 | distance = self.coordinate.distance(coordinate) | ||
| 30 | return distance <= self.radius | ||
| 31 | |||
| 32 | def x_coordinates_within_radius_at(self, y: int, map: "Map") -> Union[range, list]: | ||
| 33 | |||
| 34 | coordinate = Coordinate(self.coordinate.x, y) | ||
| 35 | |||
| 36 | if not self.within_radius(coordinate): | ||
| 37 | return [] | ||
| 38 | |||
| 39 | dy = abs(self.coordinate.y - y) | ||
| 40 | left_over = self.radius - dy | ||
| 41 | |||
| 42 | return range( | ||
| 43 | max(self.coordinate.x - left_over, map.width[0]), | ||
| 44 | min(self.coordinate.x + left_over + 1, map.width[-1]), | ||
| 45 | ) | ||
| 46 | |||
| 27 | 47 | ||
| 28 | @dataclass | 48 | @dataclass |
| 29 | class Map: | 49 | class Map: |
| @@ -77,21 +97,15 @@ class AssignmentOne(Assignment): | |||
| 77 | def run(self, input: Iterator[Tuple[Sensor, Coordinate]], y=2000000): | 97 | def run(self, input: Iterator[Tuple[Sensor, Coordinate]], y=2000000): |
| 78 | map = self.create_map(input) | 98 | map = self.create_map(input) |
| 79 | 99 | ||
| 80 | no_sensor = 0 | 100 | x_coordinates = { |
| 81 | 101 | x | |
| 82 | for x in map.width: | 102 | for sensor in map.sensors |
| 83 | coordinate = Coordinate(x, y) | 103 | for x in sensor.x_coordinates_within_radius_at(y, map) |
| 84 | 104 | } | |
| 85 | for sensor in map.sensors: | ||
| 86 | if sensor.nearest == coordinate: | ||
| 87 | break | ||
| 88 | |||
| 89 | distance = sensor.coordinate.distance(coordinate) | ||
| 90 | if distance <= sensor.radius: | ||
| 91 | no_sensor += 1 | ||
| 92 | break | ||
| 93 | 105 | ||
| 94 | return no_sensor | 106 | return len(x_coordinates) - len( |
| 107 | [beacon.x for beacon in map.beacons if beacon.y == y] | ||
| 108 | ) | ||
| 95 | 109 | ||
| 96 | 110 | ||
| 97 | class AssignmentTwo(Assignment): | 111 | class AssignmentTwo(Assignment): |
