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()