From b37323ac00baa3ac5dcc042eaad95d4dc1eeab0f Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Fri, 16 Dec 2022 11:48:40 +0100 Subject: Day 15 [WIP] --- aoc/__init__.py | 18 ++++++++++------- aoc/test_init.py | 4 +++- day15/__init__.py | 60 ++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/aoc/__init__.py b/aoc/__init__.py index 8368f7b..7a089f6 100644 --- a/aoc/__init__.py +++ b/aoc/__init__.py @@ -1,11 +1,15 @@ # -*- coding: utf-8 -*- import os from abc import ABC -from typing import Generator, Any, Iterator +from typing import Generator, Any, Iterator, Dict, TypeVar, Generic +T = TypeVar("T") +I = TypeVar("I") -class BaseAssignment(ABC): - example_result = NotImplemented + +class BaseAssignment(Generic[T, I], ABC): + example_result: T = NotImplemented + example_kwargs: Dict = {} def __init__(self, path): self.path = path @@ -13,14 +17,14 @@ class BaseAssignment(ABC): def __str__(self): return f"{self.__module__}.{self.__class__.__name__}" - def parse_item(self, item: str) -> Any: + def parse_item(self, item: str) -> I: return item @property - def part(self): + def part(self) -> int: return 1 if self.__class__.__name__.endswith("One") else 2 - def read_input(self, example=False) -> Generator: + def read_input(self, example=False) -> Iterator[I]: file = f"{self.path}/input.txt" if example or not os.path.isfile(file): @@ -35,5 +39,5 @@ class BaseAssignment(ABC): for line in input_file.readlines(): yield self.parse_item(line.strip("\n")) - def run(self, input: Iterator) -> Any: + def run(self, input: Iterator[I]) -> T: raise NotImplementedError("Please implement run") diff --git a/aoc/test_init.py b/aoc/test_init.py index f804c41..e52daf7 100644 --- a/aoc/test_init.py +++ b/aoc/test_init.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- def test_assignment_examples(assignment): assert ( - assignment.run(input=assignment.read_input(example=True)) + assignment.run( + input=assignment.read_input(example=True), **assignment.example_kwargs + ) == assignment.example_result ) diff --git a/day15/__init__.py b/day15/__init__.py index 3ba49d3..b43cae1 100644 --- a/day15/__init__.py +++ b/day15/__init__.py @@ -18,21 +18,35 @@ class Sensor: coordinate: Coordinate nearest: Coordinate + def __hash__(self): + return hash(self.coordinate) + def __post_init__(self): self.radius = self.coordinate.distance(self.nearest) @dataclass class Map: - sensors: Set[Coordinate] = field(default_factory=set) + sensors: Set[Sensor] = field(default_factory=set) beacons: Set[Coordinate] = field(default_factory=set) + def __post_init__(self): + all_coordinates = self.beacons | {sensor.coordinate for sensor in self.sensors} + + min_x = min(c.x for c in all_coordinates) + max_x = max(c.x for c in all_coordinates) + min_y = min(c.y for c in all_coordinates) + max_y = max(c.y for c in all_coordinates) + + self.width = list(range(min_x, max_x + 1)) + self.height = list(range(min_y, max_y + 1)) + input_pattern = re.compile("x=(-?[-0-9]+), y=(-?[0-9]+)") -class Assignment(BaseAssignment, ABC): - def get_coordinates(self, line: str) -> Tuple[Coordinate, Coordinate]: +class Assignment(BaseAssignment[int, Tuple[Sensor, Coordinate]], ABC): + def parse_item(self, line: str) -> Tuple[Sensor, Coordinate]: match = input_pattern.findall(line) if len(match) != 2: @@ -43,27 +57,41 @@ class Assignment(BaseAssignment, ABC): beacon = Coordinate(int(beacon_match[0]), int(beacon_match[1])) sensor = Sensor(Coordinate(int(sensor_match[0]), int(sensor_match[1])), beacon) - result = tuple(Coordinate(int(x), int(y)) for x, y in match) + return sensor, beacon - return result + def create_map(self, input: Iterator[Tuple[Sensor, Coordinate]]) -> Map: + sensors = set() + beacons = set() - def parse_input(self): - pass + for sensor, beacon in input: + sensors.add(sensor) + beacons.add(beacon) + + return Map(sensors, beacons) class AssignmentOne(Assignment): - example_result = 10 + example_result = 26 + example_kwargs = {"y": 10} - def run(self, input: Iterator) -> Any: - sensors = set() - beacons = set() + def run(self, input: Iterator[Tuple[Sensor, Coordinate]], y=2000000): + map = self.create_map(input) - for line in input: - sensor, beacon = self.get_coordinates(line) - sensors.add(sensor) - beacons.add(beacon) + no_sensor = 0 + + for x in map.width: + coordinate = Coordinate(x, y) + + for sensor in map.sensors: + if sensor.nearest == coordinate: + break + + distance = sensor.coordinate.distance(coordinate) + if distance <= sensor.radius: + no_sensor += 1 + break - pass + return no_sensor class AssignmentTwo(Assignment): -- cgit v1.2.3