Files
python-aoc-2023/day05/part2.py
Sebastian Seedorf 7a7065b04e Day 05 (optimized)
2023-12-08 12:10:12 +01:00

70 lines
2.3 KiB
Python

#!/usr/bin/env python3
from typing import List, Tuple
from tqdm import tqdm
lines = (x.strip() for x in open("input.txt"))
seeds = list(int(y) for y in next(lines)[7:].split(" "))
curr_map = None
def items_to_map(value: List[Tuple[int, int, int]]):
curr = 0
out = []
for dest, src, size in sorted(value, key=lambda x: x[1]):
if src > curr:
out.append((curr, 0))
if size > 0:
out.append((src, dest-src))
curr = src + size
out.append((curr, 0))
return out
def iter_maps(lines):
next_items = []
for line in lines:
if len(line) and line[0].isdigit():
next_items.append(tuple(int(y) for y in line.split(" ")))
elif len(next_items):
yield items_to_map(next_items)
next_items = []
if len(next_items):
yield items_to_map(next_items)
def find_largest_smaller_value(sorted_list, x):
low, high = 0, len(sorted_list)
while low < high - 1:
mid = (low + high) // 2
if sorted_list[mid][0] <= x:
low = mid
else:
high = mid
return sorted_list[low], low
def merge_maps(curr_map, next_map):
merged_map = []
for i in range(0, len(curr_map)):
dest_start = curr_map[i][0] + curr_map[i][1]
dest_start_idx = find_largest_smaller_value(next_map, dest_start)[1]
dest_end = curr_map[i + 1][0] + curr_map[i][1] - 1 if i + 1 < len(curr_map) else None
dest_end_idx = find_largest_smaller_value(next_map, dest_end)[1] if dest_end is not None else len(next_map) - 1
for next_start, next_offset in next_map[dest_start_idx:dest_end_idx + 1]:
merged_map.append((max(curr_map[i][0], next_start - curr_map[i][1]), curr_map[i][1] + next_offset))
return merged_map
for next_map in iter_maps(lines):
curr_map = next_map if curr_map is None else merge_maps(curr_map, next_map)
result = float("inf")
for i in range(0, len(seeds), 2):
dest_start = seeds[i]
dest_start_idx = find_largest_smaller_value(curr_map, dest_start)[1]
dest_end = seeds[i] + seeds[i+1] - 1
dest_end_idx = find_largest_smaller_value(curr_map, dest_end)[1]
for next_start, next_offset in curr_map[dest_start_idx:dest_end_idx + 1]:
result = min(result, next_start + next_offset)
print(result)