Advent of Code 2023 Day 5 Part 2
Mix.install([
{:kino_aoc, "~> 0.1.5"}
])
Get Inputs
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2023", "5", System.fetch_env!("LB_SESSION"))
My answer
defmodule Resolver do
def parse(input) do
input
|> String.split("\n\n")
|> Enum.into(%{}, fn group ->
group
|> String.split("\n")
|> parse_group()
end)
end
defp parse_group(group) when length(group) == 1 do
seeds =
group
|> hd()
|> String.split(" ")
|> tl()
|> Enum.map(&String.to_integer(&1))
|> Enum.chunk_every(2)
|> Enum.map(fn [start, len] ->
%{
start_index: start,
end_index: start + len - 1
}
end)
{:seeds, seeds}
end
defp parse_group(group) do
group_name =
group
|> hd()
|> String.slice(0..-6)
|> String.replace("-", "_")
|> String.to_atom()
mappings =
group
|> tl()
|> Enum.map(fn line ->
[dst, src, len] =
line
|> String.split(" ")
|> Enum.map(&String.to_integer(&1))
%{
src: src,
dst: dst,
len: len
}
end)
{group_name, mappings}
end
def resolve(maps) do
0
|> Stream.iterate(&(&1 + 1))
|> Enum.reduce_while(nil, fn location, _acc ->
seed =
location
|> reverse_search(maps.humidity_to_location)
|> reverse_search(maps.temperature_to_humidity)
|> reverse_search(maps.light_to_temperature)
|> reverse_search(maps.water_to_light)
|> reverse_search(maps.fertilizer_to_water)
|> reverse_search(maps.soil_to_fertilizer)
|> reverse_search(maps.seed_to_soil)
maps.seeds
|> Enum.any?(fn %{start_index: start_index, end_index: end_index} ->
seed >= start_index and seed <= end_index
end)
|> if do
{:halt, location}
else
{:cont, nil}
end
end)
end
defp reverse_search(key, mappings) do
target_mapping =
Enum.find(mappings, fn mapping ->
key >= mapping.dst and key <= mapping.dst + mapping.len - 1
end)
if is_nil(target_mapping) do
key
else
target_mapping.src + key - target_mapping.dst
end
end
end
maps =
"""
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
"""
|> String.slice(0..-2)
|> Resolver.parse()
Resolver.resolve(maps)
maps = Resolver.parse(puzzle_input)
Resolver.resolve(maps)