My part 2 solution feels completely fucking bonkers.
Part 1
def parse_input():
with open("input.txt", "r") as f:
input = f.readlines()
seeds = input[0].split(":")[1].split()
map = False
maps = []
values = []
for i in range(len(input)):
if input[i][0].isdigit():
map = True
dest_start, source_start, offset = input[i].split()
values.append(
dict(
dest_start=int(dest_start),
source_start=int(source_start),
offset=int(offset),
)
)
if i == len(input) - 1:
map = False
if not map and len(values) > 0:
maps.append(values)
values = []
map = False
maps = dict(
seed_to_soil=maps[0],
soil_to_fertilizer=maps[1],
fertilizer_to_water=maps[2],
water_to_light=maps[3],
light_to_temp=maps[4],
temp_to_humidity=maps[5],
humidity_to_location=maps[6],
)
return seeds, maps
def convert(value, map):
for m in map:
if value >= m["source_start"] and value <= m["source_start"] + m["offset"]:
return value + m["dest_start"] - m["source_start"]
return value
seeds, maps = parse_input()
lowest = 0
for seed in seeds:
seed = int(seed)
soil = convert(seed, maps["seed_to_soil"])
fertilizer = convert(soil, maps["soil_to_fertilizer"])
water = convert(fertilizer, maps["fertilizer_to_water"])
light = convert(water, maps["water_to_light"])
temp = convert(light, maps["light_to_temp"])
humidity = convert(temp, maps["temp_to_humidity"])
location = convert(humidity, maps["humidity_to_location"])
if lowest == 0 or location < lowest:
lowest = location
print(lowest)syntax highlighting by codehost
Fairly straightforward. If a number is between the right values, modify it to the correct value.
Part 2
def parse_input():
with open("input.txt", "r") as f:
input = f.readlines()
seeds = input[0].split(":")[1].split()
seed_ranges = []
range_container = []
for i in range(len(seeds)):
if not i % 2:
seed = dict()
seed.update(start=int(seeds[i]))
else:
seed.update(end=seed["start"] + int(seeds[i]) - 1)
range_container.append(seed)
seed_ranges.append(range_container)
range_container = []
map = False
maps = []
values = []
for i in range(len(input)):
if input[i][0].isdigit():
map = True
dest_start, source_start, offset = input[i].split()
values.append(
dict(
dest_start=int(dest_start),
source_start=int(source_start),
offset=int(offset),
)
)
if i == len(input) - 1:
map = False
if not map and len(values) > 0:
maps.append(values)
values = []
map = False
maps = dict(
seed_to_soil=maps[0],
soil_to_fertilizer=maps[1],
fertilizer_to_water=maps[2],
water_to_light=maps[3],
light_to_temp=maps[4],
temp_to_humidity=maps[5],
humidity_to_location=maps[6],
)
return seed_ranges, maps
def convert(data, map):
for source in data:
lowest = source["start"]
highest = source["end"]
for m in map:
dest_start = m["dest_start"]
source_start = m["source_start"]
offset = m["offset"]
if lowest >= source_start and lowest <= source_start + offset:
lowest += dest_start - source_start
if highest > source_start + offset:
new_source = dict(start=source_start + offset + 1, end=highest)
data.append(new_source)
highest = source_start + offset
highest += dest_start - source_start
source["start"] = lowest
source["end"] = highest
break
elif highest >= source_start and highest <= source_start + offset:
new_source = dict(start=lowest, end=source_start - 1)
data.append(new_source)
highest += dest_start - source_start
source["start"] = dest_start
source["end"] = highest
break
return data
seed_ranges, maps = parse_input()
lowest = 0
for seeds in seed_ranges:
soil = convert(seeds, maps["seed_to_soil"])
fertilizer = convert(soil, maps["soil_to_fertilizer"])
water = convert(fertilizer, maps["fertilizer_to_water"])
light = convert(water, maps["water_to_light"])
temp = convert(light, maps["light_to_temp"])
humidity = convert(temp, maps["temp_to_humidity"])
locations = convert(humidity, maps["humidity_to_location"])
for location in locations:
if lowest == 0 or location["start"] < lowest:
lowest = location["start"]
print(lowest)syntax highlighting by codehost
This could be much tidier but I'm just glad it worked. You do not need to check every individual number, just the lowest and highest for any given stretch of seed numbers. If they're both in range, great. If one of them is in range but the other isn't, split it up, convert the part that is in range, and check the left over part against other ranges instead. This took a while to wrap my head around.