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

Day 7

day7.livemd

Day 7

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

Part 1

calibrations = Kino.FS.file_path("day7-in.txt")
  |> File.read!()
  |> String.trim()
  |> String.split("\n")
  |> Enum.map(fn line ->
      {cal, nums} = String.split(line, ":", trim: true)
        |> List.to_tuple()
      cal = String.to_integer(cal)
      nums = String.trim(nums) |> String.split() |> Enum.map(&String.to_integer/1)
      {cal, nums}
    end)
defmodule Mathinator do
  def num_if_matched({expected_result, values}) do
    if expected_result in try_ops(values), do: expected_result, else: 0
  end
  
  defp try_ops([only]), do: [only]
  defp try_ops([first | rest]) do
    try_ops(rest) |> Enum.flat_map(& [first + &1, first * &1])
  end
end

start = System.monotonic_time(:microsecond)

result = calibrations
  |> Stream.map(fn {result, values} -> {result, Enum.reverse(values)} end)
  |> Stream.map(&Mathinator.num_if_matched/1)
  |> Enum.sum()

IO.puts("Result: #{result}")
elapsed = System.monotonic_time(:microsecond) - start
IO.puts "Finished in #{elapsed / 1000}ms"

Part 2

defmodule Mathinator2 do
  def num_if_matched({expected_result, values}) do
    if expected_result in try_ops(values), do: expected_result, else: 0
  end
  
  defp concat(a, b) do
    :math.pow(10, (1 + floor(:math.log10(b)))) * a + b |> round()
  end
  
  defp try_ops([only]), do: [only]
  defp try_ops([first | rest]) do
    try_ops(rest) |> Stream.flat_map(& [&1 + first, &1 * first, concat(&1, first)])
  end
end

start = System.monotonic_time(:microsecond)

result = calibrations
  |> Stream.map(fn {result, values} -> {result, Enum.reverse(values)} end)
  |> Task.async_stream(&Mathinator2.num_if_matched/1)
  |> Enum.reduce(0, fn {:ok, num}, acc -> num + acc end)

IO.puts("Result: #{result}")
elapsed = System.monotonic_time(:microsecond) - start
IO.puts "Finished in #{elapsed / 1000}ms"