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

Day7

2024/day7.livemd

Day7

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

Part1

content =
  Kino.FS.file_path("day7_1.txt")
  |> File.read!()
  |> String.split("\n", trim: true)

This day is a pretty simple parsing exercise.

We just need to get the test value, which is the first number before the ‘:’, the rest of the numbers must combine with some combination of operators into the test value.

defmodule Day7 do
  def collect_results(operators, [head | tail], results) do
    new_results =
      Enum.flat_map(operators, fn op ->
        Enum.map(results, fn n -> op.(n, head) end)
      end)

    case tail do
      [] -> new_results
      _ -> collect_results(operators, tail, new_results)
    end
  end

  def concat_integers(a, b) do
    (Integer.to_string(a) <> Integer.to_string(b))
    |> String.to_integer()
  end
end

formatted =
  content
  |> Enum.map(fn line ->
    [first, last] = String.split(line, ":")
    test_val = String.to_integer(first)

    numbers =
      String.split(last, " ", trim: true) |> Enum.map(fn n -> String.to_integer(n) end)

    {test_val, numbers}
  end)

part_1 =
  formatted
  |> Enum.map(fn {test_val, [head | tail]} ->
    if test_val in Day7.collect_results([&amp;Kernel.+/2, &amp;Kernel.*/2], tail, [head]) do
      test_val
    else
      0
    end
  end)
  |> Enum.sum()
# For part 2 we just have to add a new operation
# this is Day7.concat_integers/2
# unfortunately, converting to strings then back again is quite slow
part_2 =
  formatted
  |> Enum.map(fn {test_val, [head | tail]} ->
    if test_val in Day7.collect_results([&amp;Kernel.+/2, &amp;Kernel.*/2, &amp;Day7.concat_integers/2], tail, [head]) do
      test_val
    else
      0
    end
  end)
  |> Enum.sum()