From 21229c761821b8c0aff57ac513b7e8b1298a4db9 Mon Sep 17 00:00:00 2001 From: Ted Cassirer Date: Tue, 2 Jan 2024 16:26:05 +0700 Subject: [PATCH] Day 5 slow but working --- aoc_cas/aoc2023/day5.py | 92 +++++++++++++++++++++++++++++++++++++++ tests/fixtures/2023/5.txt | 35 +++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 aoc_cas/aoc2023/day5.py create mode 100644 tests/fixtures/2023/5.txt diff --git a/aoc_cas/aoc2023/day5.py b/aoc_cas/aoc2023/day5.py new file mode 100644 index 0000000..5b8e414 --- /dev/null +++ b/aoc_cas/aoc2023/day5.py @@ -0,0 +1,92 @@ +import dataclasses +from typing import Self + +from aocd import get_data + + +@dataclasses.dataclass(frozen=True) +class Map: + source: int + destination: int + length: int + + def __lt__(self, other: Self) -> bool: + return self.source < other.source + + @classmethod + def from_line(cls, line: str) -> Self: + destination, source, length = line.split(" ") + return Map(destination=int(destination), source=int(source), length=int(length)) + + +@dataclasses.dataclass(frozen=True) +class Transformation: + name: str + ranges: list[Map] + + @classmethod + def from_transformation_data(cls, group: str) -> Self: + name, *ranges_str = group.splitlines() + ranges: list[Map] = sorted(map(Map.from_line, ranges_str)) + return Transformation(name=name, ranges=ranges) + + def map(self, input: int) -> int: + if input < self.ranges[0].source: + return input + + for range in self.ranges: + if range.source > input: + break + if range.source + range.length > input: + d = input - range.source + if d <= range.length: + return range.destination + d + else: + break + return input + + +def parse(data: str) -> tuple[list[int], list[Transformation]]: + seeds_str, *groups = data.split("\n\n") + seeds = [int(s) for s in seeds_str.split(" ")[1:]] + transformations = list(map(Transformation.from_transformation_data, groups)) + return seeds, transformations + + +def part_a(data: str) -> int: + seeds, transformations = parse(data) + + lowest = 1 << 63 + for x in seeds: + for transformation in transformations: + x = transformation.map(x) + lowest = min(x, lowest) + return lowest + + +def part_b(data: str) -> int: + seeds, transformations = parse(data) + + lowest = 1 << 63 + seeds_to_check = sum(seeds[1::2]) + print("Seeds to check:", seeds_to_check) + + checked = 0 + for a, b in zip(seeds[::2], seeds[1::2]): + for x in range(a, a+b): + checked += 1 + if checked % 1000000 == 0: + print(checked, round(checked / seeds_to_check, 5)) + for transformation in transformations: + x = transformation.map(x) + lowest = min(x, lowest) + return lowest + + +if __name__ == "__main__": + from aoc_cas.util import solve_with_examples + + solve_with_examples(year=2023, day=5) + data = get_data(year=2023, day=5) + print(part_a(data)) + print(part_b(data)) diff --git a/tests/fixtures/2023/5.txt b/tests/fixtures/2023/5.txt new file mode 100644 index 0000000..7d5efca --- /dev/null +++ b/tests/fixtures/2023/5.txt @@ -0,0 +1,35 @@ +seeds: 79 14 55 13 + +seed-to-soil map: +50 98 2 +52 50 48 + +soil-to-fertilizer map: +0 15 37 +37 52 2 +39 0 15 + +fertilizer-to-water map: +49 53 8 +0 11 42 +42 0 7 +57 7 4 + +water-to-light map: +88 18 7 +18 25 70 + +light-to-temperature map: +45 77 23 +81 45 19 +68 64 13 + +temperature-to-humidity map: +0 69 1 +1 0 69 + +humidity-to-location map: +60 56 37 +56 93 4 +35 +46 \ No newline at end of file