import re from dataclasses import dataclass from typing import Optional, Dict, List, Tuple, OrderedDict as OrderedDictType from collections import OrderedDict @dataclass class AlmanacMap: destination: int source: int length: int def is_mapped(self, source: int) -> bool: return self.source <= source < self.source + self.length def mapped_value(self, source: int) -> Optional[int]: if not self.is_mapped(source): return None return self.destination + (source - self.source) def extract(input_file: str) -> Tuple[List[int], OrderedDictType[str, List[AlmanacMap]]]: seeds = [] maps = OrderedDict( ("seed-to-soil", []), ("soil-to-fertilizer", []), ("fertilizer-to-water", []), ("water-to-light", []), ("light-to-temperature", []), ("temperature-to-humidity", []), ("humidity-to-location", []), ) with open(input_file) as input: current_map = {} while line := input.readline(): if match := re.match("seeds: (.*)", line): for seed in match.group(1).split(" "): seeds.append(int(seed)) continue if match := re.match("([a-z-]+) map:", line): current_map = maps[match.group(1)] continue if match := re.match("([\d ]+)", line): destination, source, length = match.group(1).split(" ") current_map.append(AlmanacMap(destination=int(destination), source=int(source), length=int(length))) return seeds, maps def next_maps(a_map: AlmanacMap, map_type: str, maps: OrderedDictType[str, AlmanacMap]) -> List[AlmanacMap]: mini = a_map.destination maxi = a_map.destination + a_map.length maps_next_level = list( filter( lambda m: m.destination <= maxi and (m.destination + m.length) >= mini, maps[maps.keys().index(map_type) + 1], ) ) return maps_next_level def seed_to_location_map(maps): seed_to_location = [] for seed_group in maps["seed-to-soil"]: return seed_to_location