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

Day 03

2021/day-03.livemd

Day 03

Setup

Mix.install([{:kino, "~> 0.4.0"}])
example_input = Kino.Input.textarea("example data:")
real_input = Kino.Input.textarea("real data:")

Part 1

example_input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, "", trim: true))
|> Enum.zip()
|> Enum.map(&Enum.frequencies(Tuple.to_list(&1)))
|> Enum.reduce(["", ""], fn
  %{"0" => zero, "1" => one}, [gamma, epsilon] ->
    if zero > one, do: [gamma <> "0", epsilon <> "1"], else: [gamma <> "1", epsilon <> "0"]
end)
|> Enum.map(&amp;String.to_integer(&amp;1, 2))
|> Enum.reduce(&amp;Kernel.*(&amp;1, &amp;2))

Part 2

defmodule Filter do
  def filter(input, pred, match), do: filter(input, pred, match, 0, length(Enum.at(input, 0)))

  defp filter([filtered], _pred, _match, _at, _len), do: [filtered]
  defp filter(filtered, _pred, _match, at, at), do: filtered

  defp filter(filtered, pred, match, at, len) do
    filtered
    |> Enum.map(&amp;Enum.at(&amp;1, at))
    |> Enum.frequencies()
    |> Map.values()
    |> then(&amp;filter(filtered, pred, match, at, len, &amp;1))
  end

  defp filter(filtered, pred, match, at, len, [same, same]) do
    Enum.filter(filtered, &amp;(Enum.at(&amp;1, at) == match))
    |> filter(pred, match, at + 1, len)
  end

  defp filter(filtered, pred, match, at, len, [_only]) do
    Enum.filter(filtered, &amp;(Enum.at(&amp;1, at) == match))
    |> filter(pred, match, at + 1, len)
  end

  defp filter(filtered, pred, match, at, len, [zero, one]) do
    filtered =
      if pred.(zero, one) do
        Enum.filter(filtered, &amp;(Enum.at(&amp;1, at) == "0"))
      else
        Enum.filter(filtered, &amp;(Enum.at(&amp;1, at) == "1"))
      end

    filter(filtered, pred, match, at + 1, len)
  end
end

real_input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(&amp;String.split(&amp;1, "", trim: true))
|> then(fn input ->
  [
    Filter.filter(input, &amp;Kernel.>/2, "1")
    |> Enum.map(&amp;Enum.join/1)
    |> Enum.map(&amp;String.to_integer(&amp;1, 2)),
    Filter.filter(input, &amp;Kernel. Enum.map(&amp;Enum.join/1)
    |> Enum.map(&amp;String.to_integer(&amp;1, 2))
  ]
end)
|> List.flatten()
|> Enum.reduce(&amp;Kernel.*(&amp;1, &amp;2))