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"},
  {:nx, "~> 0.9.2"}
])

Inputs

input_box = Kino.Input.textarea("input")
input =
  input_box
  |> Kino.Input.read()
  |> String.split("\n")
  |> Enum.map(fn line ->
    [left, right] = String.split(line, ": ")

    right =
      right
      |> String.split(" ")
      |> Enum.map(&String.to_integer/1)

    {String.to_integer(left), right}
  end)

Part 1

defmodule FastCheck do
  def check(expected, [], acc), do: acc == expected
  def check(expected, _numbers, acc) when acc > expected, do: false

  def check(expected, [head | tail], acc), do:
    check(expected, tail, acc * head) ||
      check(expected, tail, acc + head)
end

input
|> Task.async_stream(fn {expected, [acc | numbers]} ->
  if FastCheck.check(expected, numbers, acc), do: expected, else: 0
end)
|> Enum.map(&elem(&1, 1))
|> Enum.sum()

Part 2

defmodule FastCheck2 do
  defp num_digits(num, acc) when num > 0, do:
    num_digits(div(num, 10), acc + 1)

  defp num_digits(_num, acc), do: acc

  defp concat_numbers(l, r), do:
    (l * (10 ** num_digits(r, 0))) + r

  def check(expected, [], acc), do: acc == expected
  def check(expected, _numbers, acc) when acc > expected, do: false

  def check(expected, [head | tail], acc), do:
    check(expected, tail, acc * head) ||
      check(expected, tail, acc + head) ||
      check(expected, tail, concat_numbers(acc, head))
end

input
|> Task.async_stream(fn {expected, [acc | numbers]} ->
  if FastCheck2.check(expected, numbers, acc), do: expected, else: 0
end)
|> Enum.map(&elem(&1, 1))
|> Enum.sum()