advent-of-code-2025/day05.py
Tobias Radloff 2fa934b2d0 Day 5
2025-12-05 17:53:51 +01:00

130 lines
3.4 KiB
Python

#!/usr/bin/env python
# https://adventofcode.com/2025/day/5
f = open("day05input.txt", "r")
#f = open("testinput.txt", "r")
d = [l.strip() for l in f.readlines()]
# prepare data
if "" in d:
i = d.index("")
Ranges = [[int(r.split("-")[0]), int(r.split("-")[1])] for r in d[:i]]
IDs = list(map(int, d[i+1:]))
else:
Ranges = [[int(r.split("-")[0]), int(r.split("-")[1])] for r in d]
def part1(ranges: list[list[int, int]], ids: list[int]) -> int:
for r in ranges:
assert int(r[0]) <= int(r[1])
total = 0
# loop over IDs
for _id in ids:
id_counter = 0
# loop over ranges
for r in ranges:
if r[0] <= _id <= r[1]:
total += 1
break
return total
def part2(ranges: list[list[int, int]]) -> int:
for r in ranges:
assert int(r[0]) <= int(r[1])
distinct_ranges = []
# integrates current range with current list of distinct ranges
# returns true if a change was made to distinct_ranges
def compare(c_range: list[int, int]) -> bool:
r_min, r_max = c_range
# checks subcase
def subcase():
# subcase a: it's the last distinct range or the range ends before the next distinct range starts
if i == len(distinct_ranges) - 1 or r_max < distinct_ranges[i + 1][0]:
d_range[1] = r_max
# subcase b: range ends inside next distinct range
elif distinct_ranges[i + 1][0] <= r_max <= distinct_ranges[i + 1][1]:
d_range[1] = distinct_ranges[i + 1][1]
distinct_ranges.pop(i + 1)
# subcase c: range stretches beyond the end of the next distinct range
# I'll ignore this case b/c I think it doesn't occur
else:
raise Exception("Shit, I missed a subcase!")
# loop over distinct ranges
for i in range(len(distinct_ranges)):
d_range = distinct_ranges[i]
# case 1: range sits completely outside current distinct range
if r_max < d_range[0] or d_range[1] < r_min:
continue
# case 2: range sits inside the current distinct range
elif d_range[0] <= r_min <= r_max <= d_range[1]:
return False
# case 3: range spans from outside into current distant range, but not beyond
elif r_min < d_range[0] <= r_max <= d_range[1]:
d_range[0] = r_min
return True
# case 4: range spans from inside the current distance range beyond its end
elif d_range[0] <= r_min <= d_range[1] < r_max:
subcase()
return True
# case 5: range completely envelops current distant range
elif r_min < d_range[0] < d_range[1] < r_max:
d_range[0] = r_min
subcase()
return True
# case 6: I missed a case
else:
raise Exception("Shit, I missed a case!")
distinct_ranges.append(c_range)
distinct_ranges.sort(key=lambda a: a[0])
return True
# compute ranges with no overlaps
for r in ranges:
# print(distinct_ranges)
# no distinct ranges yet?
if len(distinct_ranges) == 0:
distinct_ranges.append(r)
continue
# compare new range to all distinct ranges computed so far
# repeat until no changes happened
while True:
has_changed = compare(r)
# make sure distinct ranges never overlap
assert all([distinct_ranges[j+1][0] - distinct_ranges[j][1] > 0 for j in range (len(distinct_ranges) - 1)])
if not has_changed:
break
return sum([r[1] - r[0] + 1 for r in distinct_ranges])
#print(part1(Ranges, IDs))
print(part2(Ranges))