From 3b8a0f9990cbd10170fb563490f28a6bd84eea1b Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Tue, 5 Dec 2023 10:06:58 +0100 Subject: Day5 part 1 --- day5/__init__.py | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 day5/__init__.py (limited to 'day5/__init__.py') diff --git a/day5/__init__.py b/day5/__init__.py new file mode 100644 index 0000000..3189a07 --- /dev/null +++ b/day5/__init__.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +from abc import ABC +from dataclasses import dataclass +from multiprocessing import Pool +from typing import Iterator + +from aoc import BaseAssignment + + +@dataclass +class InnerMapping: + source: int + destination: int + length: int + + def __getitem__(self, item): + if self.source <= item < self.source + self.length: + return self.destination + item - self.source + raise KeyError() + + +class Mapping: + def __init__(self): + self.mappings = [] + + def __getitem__(self, item): + for mapping in self.mappings: + try: + return mapping[item] + except KeyError: + continue + + return item + + def update(self, source: int, destination: int, length: int): + self.mappings.append(InnerMapping(source, destination, length)) + + +I = tuple[list[int], list[Mapping]] +T = int + + +class Assignment(BaseAssignment, ABC): + @staticmethod + def map_seed_position(seed: int, mappings: list[Mapping]) -> int: + value = seed + for item in mappings: + value = item[value] + + return value + + def read_input(self, example=False) -> I: + seeds, *almanac = super().read_input(example) + _, seeds = seeds.split(": ") + seeds = [int(i) for i in seeds.split(" ")] + + maps: list[Mapping] = [] + map = None + + index = 0 + while True: + try: + line = almanac[index] + except IndexError: + break + + if line == "": + index += 2 + + if map is not None: + maps.append(map) + map = None + + continue + else: + index += 1 + + if map is None: + map = Mapping() + + destination, source, length = line.split(" ") + map.update(int(source), int(destination), int(length)) + + return seeds, [*maps, map] + + +class AssignmentOne(Assignment): + example_result = 35 + + def run(self, input: I) -> T: + seeds, almanac = input + + values = [] + for seed in seeds: + values.append(self.map_seed_position(int(seed), almanac)) + + return min(values) + + +def run_per_seed_range(index: int, seeds: list[int], almanac: list[Mapping]): + seed, length = int(seeds[index]), int(seeds[index + 1]) + + value = None + for seed in range(seed, seed + length): + location = Assignment.map_seed_position(seed, almanac) + if value is None or value > location: + value = location + + return value + + +class AssignmentTwo(Assignment): + example_result = 46 + + def run(self, input: I) -> T: + seeds, almanac = input + + value = None + + with Pool(processes=len(seeds) // 2) as pool: + for v in pool.imap_unordered( + lambda index: run_per_seed_range(index, seeds, almanac), + range(0, len(seeds), 2), + ): + if value is None or value > v: + value = v + + return value -- cgit v1.2.3