Powered by AppSignal & Oban Pro

AoC: Day 1

day_1/livebook.livemd

AoC: Day 1

Part I

{:ok, contents} = File.read("/Users/kappa/Code/Elixir/AoC/Day 1/day_1_input_1.txt")

contents
|> String.split(~r/\n/)
|> Enum.map(fn s -> Regex.scan(~r/\d+/, s) end)
|> Enum.map(&Enum.join/1)
|> Enum.map(fn s -> [String.at(s, 0), String.at(s, -1)] end)
|> Enum.map(fn l -> Enum.join(l) end)
|> Enum.map(fn n ->
  case Integer.parse(n) do
    {int, _rest} -> int
    _ -> 0
  end
end)
|> Enum.sum()
55712

Part II

{:ok, contents} = File.read("/Users/kappa/Code/Elixir/AoC/Day 1/day_1_input_1.txt")

number_names = %{
  one: "1",
  two: "2",
  three: "3",
  four: "4",
  five: "5",
  six: "6",
  seven: "7",
  eight: "8",
  nine: "9"
}

maybe_cast_value = fn x ->
  Map.get(number_names, String.to_atom(x), x)
end

find_first_and_last_number = fn str ->
  s_number_names = Enum.map(Map.keys(number_names), fn name -> Atom.to_string(name) end)

  str
  # Split the string into graphemes
  |> String.graphemes()
  |> Enum.reduce({nil, "", nil}, fn char, {first_match, current, last_match} ->
    new_current = current <> char

    match =
      if Regex.match?(~r/\d/, char),
        do: char,
        else: Enum.find(s_number_names, &String.ends_with?(new_current, &1))

    new_first_match = if first_match, do: first_match, else: match
    new_last_match = if match, do: match, else: last_match

    {new_first_match, new_current, new_last_match}
  end)
  # Extract the first and last match
  |> (fn {first, _, last} -> [first, last] end).()
end

contents
|> String.split(~r/\n/)
|> Enum.map(fn str -> find_first_and_last_number.(str) end)
|> Enum.reject(fn ls -> List.first(ls) == nil or List.last(ls) == nil end)
|> Enum.map(fn ls ->
  [maybe_cast_value.(List.first(ls)), maybe_cast_value.(List.last(ls))]
end)
|> Enum.map(fn l -> Enum.join(l) end)
|> Enum.map(fn n ->
  case Integer.parse(n) do
    {int, _rest} -> int
    _ -> 0
  end
end)
|> Enum.sum()
55413