86 lines
2.1 KiB
Elixir
86 lines
2.1 KiB
Elixir
defmodule Aoc2023.Day5 do
|
|
use Aoc2023
|
|
|
|
defp numbers(str), do: str |> String.split() |> Enum.map(&String.to_integer/1)
|
|
|
|
def parse(input) do
|
|
[seeds | maps] =
|
|
input
|
|
|> String.split("\n\n")
|
|
|
|
{
|
|
seeds |> String.split(": ") |> Enum.at(1) |> numbers,
|
|
maps
|
|
|> Enum.map(pipe(
|
|
String.split("\n")
|
|
|> tail
|
|
|> Enum.map(pipe(
|
|
numbers
|
|
|> List.to_tuple()
|
|
|> then(fn {dst, src, len} -> {src .. (src + len - 1), dst - src} end)
|
|
))
|
|
))
|
|
}
|
|
end
|
|
|
|
defp split_range_on(r1, r2) do
|
|
cond do
|
|
Range.disjoint?(r1, r2) -> {[r1], []}
|
|
r1.first < r2.first && r1.last < r2.last ->
|
|
{a, b} = Range.split(r1, r2.first - r1.first)
|
|
{[a], [b]}
|
|
r1.first > r2.first && r1.last > r2.last ->
|
|
{a, b} = Range.split(r1, r1.first - r2.first)
|
|
{[b], [a]}
|
|
r1.first >= r2.first && r1.last <= r2.last ->
|
|
{[], [r1]}
|
|
r1.first <= r2.first && r1.last >= r2.last
|
|
or r1.first ->
|
|
{pre, rest} = Range.split(r1, r2.first - r1.first)
|
|
{mid, last} = Range.split(rest, r2.last - rest.first)
|
|
{[pre, last], [mid]}
|
|
end
|
|
end
|
|
|
|
defp map(loc, map) do
|
|
{unmapped, mapped} = for {src, offset} <- map,
|
|
reduce: {[loc], []} do
|
|
{unmapped, mapped} ->
|
|
for range <- unmapped,
|
|
reduce: {[], mapped} do
|
|
{unmapped_, mapped_} ->
|
|
{unmapped, mapped} = split_range_on(range, src)
|
|
{
|
|
unmapped_ ++ unmapped,
|
|
mapped_ ++ Enum.map(mapped, &(Range.shift(&1, offset)))
|
|
}
|
|
end
|
|
end
|
|
unmapped ++ mapped
|
|
end
|
|
|
|
defp run(seeds, maps) do
|
|
for seed <- seeds do
|
|
for map <- maps, reduce: [seed] do
|
|
loc ->
|
|
loc
|
|
|> Enum.flat_map(pipe(map(map)))
|
|
end
|
|
end
|
|
|> Enum.flat_map(&id/1)
|
|
|> Enum.min_by(&(&1.first))
|
|
|> then(&(&1.first))
|
|
end
|
|
|
|
def part1({seeds, maps}) do
|
|
run(seeds |> Enum.map(&(&1..&1)), maps)
|
|
end
|
|
|
|
def part2({seeds, maps}) do
|
|
run(
|
|
seeds |> Enum.chunk_every(2) |> Enum.map(fn [s, len] -> s..(s + len - 1) end),
|
|
maps
|
|
)
|
|
end
|
|
end
|