JonathanGupton

Advent of Code 2025 - Day 05 - Python

Dec 5th, 2025
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.17 KB | None | 0 0
  1. from collections import deque
  2.  
  3.  
  4. def parse_data(fp: str) -> tuple[list[tuple[int, int]], list[int]]:
  5.     range_collection = []
  6.     num_collection = []
  7.     with open(fp, "r") as f:
  8.         data = f.read()
  9.         ranges, nums = data.split("\n\n")
  10.  
  11.         for line in ranges.split("\n"):
  12.             l, r = map(int, line.split("-"))
  13.             range_collection.append((l, r))
  14.         for n in map(int, nums.split("\n")):
  15.             num_collection.append(n)
  16.     return range_collection, num_collection
  17.  
  18.  
  19. def is_fresh(i: int, rngs: list[tuple[int, int]]) -> bool:
  20.     """
  21.    >>> assert is_fresh(1, [range(3, 6), range(10, 15), range(16, 21), range(12, 19)]) is False
  22.    >>> assert is_fresh(5, [range(3, 6), range(10, 15), range(16, 21), range(12, 19)]) is True
  23.    >>> assert is_fresh(8, [range(3, 6), range(10, 15), range(16, 21), range(12, 19)]) is False
  24.    >>> assert is_fresh(11,[range(3, 6), range(10, 15), range(16, 21), range(12, 19)]) is True
  25.    >>> assert is_fresh(17,[range(3, 6), range(10, 15), range(16, 21), range(12, 19)]) is True
  26.    >>> assert is_fresh(32,[range(3, 6), range(10, 15), range(16, 21), range(12, 19)]) is False
  27.    """
  28.     return any(i in r for r in rngs)
  29.  
  30.  
  31. def count_fresh(nums: list[int], ranges: list[range]) -> int:
  32.     fresh_count = 0
  33.     for i in nums:
  34.         if is_fresh(i, ranges):
  35.             fresh_count += 1
  36.     return fresh_count
  37.  
  38.  
  39. def calculate_all_fresh(rngs: list[range]) -> int:
  40.     """
  41.    >>> assert calculate_all_fresh([range(3, 6), range(10, 15), range(16, 21), range(12, 19)]) == 14
  42.    """
  43.     rngs = sorted(rngs, key=lambda x: x[0])
  44.     d = deque(rngs)
  45.     fresh_count = 0
  46.     min_val, max_val = 0, 0
  47.     while d:
  48.         l = d.popleft()
  49.         min_val = l.start
  50.         max_val = l.stop
  51.         while d:
  52.             r = d.popleft()
  53.             if r.start > max_val:
  54.                 fresh_count += max_val - min_val
  55.                 d.appendleft(r)
  56.                 break
  57.             elif (r.start < max_val) and (
  58.                 r.stop < max_val
  59.             ):  # next range is inclusive in prior ranges
  60.                 continue
  61.             else:  # next range min in prior range, max val extends range
  62.                 max_val = r.stop
  63.     fresh_count += max_val - min_val # capture final range
  64.     return fresh_count
  65.  
  66.  
  67. def convert_to_ranges(rngs: list[tuple[int, int]]) -> list[range]:
  68.     return [range(a, b + 1) for a, b in rngs]
  69.  
  70.  
  71. def part_a():
  72.     """
  73.    >>> fp = "day05a.txt"
  74.    >>> rngs, vegetables = parse_data(fp)
  75.    >>> ranges = convert_to_ranges(rngs)
  76.    >>> count = count_fresh(vegetables, ranges)
  77.    >>> assert count == 3
  78.    """
  79.     fp = "day05.txt"
  80.     rngs, vegetables = parse_data(fp)
  81.     ranges = convert_to_ranges(rngs)
  82.     count = count_fresh(vegetables, ranges)
  83.     print(count)
  84.  
  85.  
  86. def part_b():
  87.     """
  88.    >>> fp = "day05a.txt"
  89.    >>> rngs, _ = parse_data(fp)
  90.    >>> rngs = convert_to_ranges(rngs)
  91.    >>> assert calculate_all_fresh(rngs) == 14
  92.    """
  93.     fp = "day05.txt"
  94.     rngs, _ = parse_data(fp)
  95.     rngs = convert_to_ranges(rngs)
  96.     all_fresh = calculate_all_fresh(rngs)
  97.     print(all_fresh)
  98.  
  99.  
  100. if __name__ == "__main__":
  101.     part_a()
  102.     part_b()
  103.  
Advertisement
Add Comment
Please, Sign In to add comment