|
|
@@ -4,6 +4,14 @@ helper = Helper(debug=True) |
|
|
|
load_input = helper.load_input |
|
|
|
debug = helper.debug |
|
|
|
|
|
|
|
# FUTURE ME: HERE'S THE KEY |
|
|
|
# You don't have to check every seed. |
|
|
|
# Instead, create ranges, and use the later steps to cut those ranges |
|
|
|
# into chunks. The smallest value in the smallest chunk after the last |
|
|
|
# step is the solution. The brute-force solution takes an enormous amount |
|
|
|
# of time; the chunk solution is still polynomial time, I think, but |
|
|
|
# the n is much smaller (dozens rather than hundreds of millions). |
|
|
|
|
|
|
|
def within(target, start, end): |
|
|
|
if start == end: |
|
|
|
return target == start |
|
|
@@ -11,6 +19,40 @@ def within(target, start, end): |
|
|
|
start, end = end, start |
|
|
|
return target >= start and end >= target |
|
|
|
|
|
|
|
def chunk_it(old_range, new_range): |
|
|
|
o_start, o_end = old_range |
|
|
|
n_start, n_end = new_range |
|
|
|
debug(o_start, o_end, n_start, n_end) |
|
|
|
|
|
|
|
# The new range is entirely outside the current range |
|
|
|
if n_end < o_start or n_start > o_end: |
|
|
|
debug("Entirely outside!") |
|
|
|
return sorted([old_range, new_range], key=lambda n:n[0]) |
|
|
|
|
|
|
|
# The new range is entirely within the current range |
|
|
|
if n_start >= o_start and n_end <= o_end: |
|
|
|
# We've already accounted for this range |
|
|
|
debug("Already got it") |
|
|
|
return [old_range] |
|
|
|
|
|
|
|
# The new range starts lower and ends higher |
|
|
|
if n_start <= o_start and n_end >= o_end: |
|
|
|
# We can replace the old range with the new one |
|
|
|
debug("Replacement!") |
|
|
|
return [new_range] |
|
|
|
|
|
|
|
# The new range starts lower but ends within |
|
|
|
if n_start <= o_start and n_end >= o_start and n_end <= o_end: |
|
|
|
debug("Starts before") |
|
|
|
return [[n_start, o_end]] |
|
|
|
|
|
|
|
# The new range starts within but ends higher |
|
|
|
if n_end >= o_end and n_start >= o_start and n_start <= o_end: |
|
|
|
debug("Ends after") |
|
|
|
return [[o_start, n_end]] |
|
|
|
|
|
|
|
raise Exception(f"What? What? Nothing matched: {old_range}, {new_range}") |
|
|
|
|
|
|
|
def main(): |
|
|
|
lines = load_input(5) |
|
|
|
|
|
|
@@ -26,10 +68,29 @@ def main(): |
|
|
|
} |
|
|
|
maps_keys = list(maps_dict.keys()) |
|
|
|
maps_dict["seeds"] = [int(n) for n in lines[0].split()[1:]] |
|
|
|
debug(f"Starting with {len(maps_dict['seeds'])//2} ranges") |
|
|
|
real_seeds = [] |
|
|
|
i, j = 0, 1 |
|
|
|
while j < len(maps_dict["seeds"]): |
|
|
|
real_seeds.append((maps_dict["seeds"][i], maps_dict["seeds"][i] + maps_dict["seeds"][j])) |
|
|
|
new_range = [maps_dict["seeds"][i], maps_dict["seeds"][i] + maps_dict["seeds"][j]] |
|
|
|
if len(real_seeds) == 0: |
|
|
|
real_seeds.append(new_range) |
|
|
|
else: |
|
|
|
new_real_seeds = [] |
|
|
|
for range in real_seeds: |
|
|
|
add_ranges = chunk_it(range, new_range) |
|
|
|
debug(add_ranges) |
|
|
|
for r in add_ranges: |
|
|
|
if r not in new_real_seeds: |
|
|
|
new_real_seeds.append(r) |
|
|
|
real_seeds = list(new_real_seeds) |
|
|
|
i += 2 |
|
|
|
j += 2 |
|
|
|
debug(real_seeds, i, j) |
|
|
|
debug(f"Found {len(real_seeds)} actual ranges") |
|
|
|
real_seeds.sort(key=lambda n: n[0]) |
|
|
|
# debug(real_seeds) |
|
|
|
return |
|
|
|
# new_start = maps_dict["seeds"][i] |
|
|
|
# new_end = new_start + maps_dict["seeds"][j] |
|
|
|
# debug(f"Adding seeds in range {new_start}-{new_end}") |
|
|
@@ -37,8 +98,6 @@ def main(): |
|
|
|
# debug(new_seeds) |
|
|
|
# real_seeds.append(new_seeds) |
|
|
|
# debug(real_seeds) |
|
|
|
i += 2 |
|
|
|
j += 2 |
|
|
|
seeds_list = [{"seed": seed[1]} for seed in real_seeds] |
|
|
|
|
|
|
|
current_key = "" |