Again part 2 took me way longer than I would've liked and also than feels appropriate for the simplicity of the solution I finally came up with.
Turned out quite fast, thanks to the ranges.
Python
from pathlib import Path
from typing import List
from itertools import combinations
def parse_input(input: str) -> tuple[set[range], list[int]]:
parts = input.split("\n\n")
fresh = set((lambda r: range(int(r[0]), int(r[1]) + 1))(line.split("-")) for line in parts[0].splitlines())
return (fresh, list(map(int, parts[1].splitlines())))
def merge_ranges(a: range, b: range) -> List[range]:
if a.stop <= b.start or b.stop <= a.start:
return [a, b]
return [range(min(a.start, b.start), max(a.stop, b.stop))]
def part_one(input: str) -> int:
fresh, available = parse_input(input)
return len(list(filter(None, [any(i in r for r in fresh) for i in available])))
def part_two(input: str) -> int:
fresh, _ = parse_input(input)
while True:
for a, b in combinations(fresh, 2):
if len(m := merge_ranges(a, b)) == 1:
fresh.remove(a)
fresh.remove(b)
fresh.add(m[0])
break
else:
break
return sum(map(len, fresh))
if __name__ == "__main__":
input = Path("_2025/_5/input").read_text("utf-8")
print(part_one(input))
print(part_two(input))