import shared from pprint import pprint from dataclasses import dataclass @dataclass class Mapping: dst: int src: int ran: int # RANGE maps_parts = [ "seed-to-soil", "soil-to-fertilizer", "fertilizer-to-water", "water-to-light", "light-to-temperature", "temperature-to-humidity", "humidity-to-location", ] group = lambda l,s: list(zip(*(iter(l),) * s)) def line_ints(s): return [int(x) for x in s.split() if s] def parse_line(line): return Mapping(*line) class Mapper: def __init__(self, rows): self.parse(rows) def parse(self, rows): seeds = rows.pop(0) rows.pop(0) # Discard empty to start at a clean slate seeds = line_ints(seeds.split(":")[1]) maps = {} current_map = None for row in rows: if ":" in row: current_map = row[:-5] maps[current_map] = [] continue if row == "": continue maps[current_map].append(parse_line(line_ints(row))) self.seeds = seeds self.maps = maps def calculate(self, step, source): possibilities = self.maps[step] for p in possibilities: if source < p.src: #print(f"\t{source} less than {p.src}") continue if source > p.src+ p.ran: #print(f"\t{source} greater than {p.src}+{p.ran}={p.src+p.ran}") continue #print(f"\t{source} in range") #print(f"\t{source} is {p.dst + (source - p.src)}") return p.dst + (source - p.src) break return source # @shared.profile def part1(rows): mapper = Mapper(rows[:]) locations = [] for seed in mapper.seeds: next = seed for part in maps_parts: _part = next next = mapper.calculate(part, next) locations.append(next) print(locations) print(min(locations)) # @shared.profile def part2(rows): mapper = Mapper(rows[:]) locations = [] seeds = group(mapper.seeds, 2) for seed_group in seeds: for seed in range(seed_group[0], seed_group[0]+seed_group[1]): next = seed for part in maps_parts: _part = next next = mapper.calculate(part, next) locations.append(next) print(min(locations)) def main(): rows = [row for row in shared.load_rows(5)] with shared.elapsed_timer() as elapsed: part1(rows) print("🕒", elapsed()) with shared.elapsed_timer() as elapsed: part2(rows) print("🕒", elapsed()) if __name__ == "__main__": main()