This repository has been archived on 2024-12-22. You can view files and clone it, but cannot push or open issues or pull requests.
aoc2023/d5.py
2023-12-06 11:47:04 -05:00

164 lines
4.7 KiB
Python

EXAMPLE = """
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
"""
def clean(text: str) -> list[str]:
return list(text.splitlines())
def solve(lines: list[str]):
seeds = []
idx = -1
maps = []
for (_, line) in enumerate(lines):
if line.startswith("seeds:"):
seeds = map(int, line.replace("seeds:", "").strip().split(" "))
continue
if line.strip() == "":
continue
if "map" in line:
maps.append([])
idx += 1
continue
else:
maps[idx].append(list(map(int, line.split(" "))))
locs = []
for current in seeds:
for m in maps:
for mapping in m:
dest_range_start, source_range_start, range_len = mapping
if current >= source_range_start and current < source_range_start + range_len:
current = dest_range_start + (current - source_range_start)
break
else:
current = current
locs.append(current)
return min(locs)
def solve2(lines: list[str]):
seeds = []
idx = -1
maps = []
for (_, line) in enumerate(lines):
if line.startswith("seeds:"):
all_seeds = []
seeds = list(map(int, line.replace("seeds:", "").strip().split(" ")))
for i in range(0, len(seeds), 2):
all_seeds.append(seeds[i:i+2])
seeds = all_seeds
continue
if line.strip() == "":
continue
if "map" in line:
maps.append([])
idx += 1
continue
else:
maps[idx].append(list(map(int, line.split(" "))))
# source: |---------------------|
# seeds:
# |---|
# aaaaaabbbb
# aaaaaabbbbbbbbbbbbbbbbbbbbbbcccc
# aaaaaaaaaaaaaaaa
# aaaaaaaaaaaaaaaaaaaccccc
# |-------|
for m in maps:
next_seeds = []
while seeds:
seed_start, seed_range = seeds.pop()
seed_end = seed_start + seed_range
for mapping in m:
dest_start, source_start, m_range = mapping
source_end = source_start + m_range
if seed_end <= source_start:
continue
elif seed_start < source_start and seed_end <= source_end:
a_range = source_start - seed_start
seeds.append([seed_start, a_range])
b_range = seed_end - source_start
next_seeds.append([dest_start, b_range])
break
elif seed_start < source_start and seed_end > source_end:
a_range = source_start - seed_start
seeds.append([seed_start, a_range])
next_seeds.append([dest_start, m_range]) # b range
c_range = seed_end - source_end
next_seeds.append([source_end, c_range])
break
elif seed_start >= source_start and seed_end <= source_end:
new_seed_start = dest_start + (seed_start - source_start)
next_seeds.append([new_seed_start, seed_range])
break
elif seed_start >= source_start and seed_start < source_end:
new_seed_start = dest_start + (seed_start - source_start)
a_range = source_end - seed_start
next_seeds.append([new_seed_start, a_range])
c_range = seed_end - source_end
seeds.append([source_end, c_range])
break
elif seed_start >= source_end:
continue
else:
print(f"{seed_start=} {seed_range=} {seed_end=}")
print(f"{source_start=} {source_end=}")
raise Exception("Unexpected case")
else:
next_seeds.append([seed_start, seed_range])
seeds = next_seeds
return min(seeds)[0]
def main():
example = clean(EXAMPLE)
print("Example 1:", solve(example))
data = clean(open("i5.txt").read())
print("Solution 1:", solve(data))
example = clean(EXAMPLE)
print("Example 2:", solve2(example))
data = clean(open("i5.txt").read())
print("Solution 2:", solve2(data))
assert(solve2(data) == 63179500)
if __name__ == "__main__":
main()