Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 5

2023/day05.livemd

Day 5

Mix.install([
  {:kino, "~> 0.11.0"}
])

Section

input = Kino.Input.textarea("Input")
input
|> Kino.Input.read()
|> String.split("\n\n")
|> then(fn [seeds | maps] ->
  maps
  |> Enum.map(fn map ->
    map
    |> String.split("\n")
    |> Enum.drop(1)
    |> Enum.map(fn mapping ->
      mapping
      |> String.split(" ", trim: true)
      |> Enum.map(&String.to_integer/1)
      |> then(fn [dst, src, size] ->
        {src..(src + size - 1), dst - src}
      end)
    end)
  end)
  |> then(fn maps ->
    seeds
    |> String.split(" ")
    |> Enum.drop(1)
    |> Enum.map(&String.to_integer/1)
    |> Enum.map(fn seed ->
      Enum.reduce(maps, seed, fn map, seed ->
        Enum.find_value(map, seed, fn {range, step} ->
          if seed in range, do: seed + step
        end)
      end)
    end)
    |> Enum.min()
  end)
end)
input
|> Kino.Input.read()
|> String.split("\n\n")
|> then(fn [seeds | maps] ->
  maps
  |> Enum.map(fn map ->
    map
    |> String.split("\n")
    |> Enum.drop(1)
    |> Enum.map(fn mapping ->
      mapping
      |> String.split(" ", trim: true)
      |> Enum.map(&String.to_integer/1)
      |> then(fn [dst, src, size] ->
        {src..(src + size - 1), dst - src}
      end)
    end)
    |> Enum.sort_by(&Enum.min(elem(&1, 0)))
    |> then(fn
      [{0.._, _} | _] = list -> list
      [{n.._, _} | _] = list -> [{0..(n - 1), 0} | list]
    end)
    |> Enum.chunk_every(2, 1)
    |> Enum.flat_map(fn
      [{_..max1, _} = head, {min2.._, _}] when max1 + 1 == min2 ->
        [head]

      [{_..max1, _} = head, {min2.._, _}] ->
        [head, {(max1 + 1)..(min2 - 1), 0}]

      [{_..max, _} = rest] ->
        [rest, {(max + 1)..((max + 1) * 10), 0}]
    end)
  end)
  |> then(fn maps ->
    seeds
    |> String.split(" ")
    |> Enum.drop(1)
    |> Enum.map(&String.to_integer/1)
    |> Enum.chunk_every(2)
    |> Enum.map(fn [start, step] -> start..(start + step - 1) end)
    |> then(fn seeds ->
      Enum.reduce(maps, seeds, fn map, seeds ->
        Enum.flat_map(seeds, fn min..max ->
          Enum.reduce(map, [], fn
            {lower..upper, _step}, acc when upper < min or lower > max ->
              acc

            {lower..upper, step}, acc ->
              [Range.shift(max(min, lower)..min(max, upper), step) | acc]
          end)
        end)
      end)
    end)
  end)
  |> Enum.min()
end)
|> Enum.min()