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

Advent of Code 2023 Day 5 Part 1

2023_day5_part1.livemd

Advent of Code 2023 Day 5 Part 1

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")
    |> split_by_blank_line([])
    |> Enum.into(%{}, fn group ->
      parse_group(group)
    end)
  end

  defp split_by_blank_line(lines, acc) do
    {head, tail} =
      Enum.split_while(lines, fn line -> line != "" end)

    if Enum.count(tail) == 0 do
      acc ++ [head]
    else
      tail
      |> tl()
      |> split_by_blank_line(acc ++ [head])
    end
  end

  defp parse_group(group) when length(group) == 1 do
    seeds =
      group
      |> hd()
      |> String.split(" ")
      |> tl()
      |> Enum.map(&String.to_integer(&1))

    {: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
    maps.seeds
    |> Enum.map(fn seed ->
      seed
      |> search(maps.seed_to_soil)
      |> search(maps.soil_to_fertilizer)
      |> search(maps.fertilizer_to_water)
      |> search(maps.water_to_light)
      |> search(maps.light_to_temperature)
      |> search(maps.temperature_to_humidity)
      |> search(maps.humidity_to_location)
    end)
    |> Enum.min()
  end

  defp search(key, mappings) do
    target_mapping =
      Enum.find(mappings, fn mapping ->
        key >= mapping.src and key <= mapping.src + mapping.len - 1
      end)

    if is_nil(target_mapping) do
      key
    else
      target_mapping.dst + key - target_mapping.src
    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)