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

Day 3: Binary Diagnostic

2021/elixir/day-03.livemd

Day 3: Binary Diagnostic

Setup

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

Input

input = Kino.Input.textarea("Input")

Part 1

defmodule M do
  def calc(freq, func) do
    freq
    |> Enum.map(&func.(&1, fn r -> elem(r, 1) end))
    |> Enum.map(&elem(&1, 0))
    |> List.to_string()
    |> String.to_integer(2)
  end
end

Kino.Input.read(input)
|> String.split()
|> Enum.map(&String.to_charlist/1)
|> Enum.zip()
|> Enum.map(&Tuple.to_list/1)
|> Enum.map(&Enum.frequencies/1)
|> then(fn freq ->
  M.calc(freq, &Enum.max_by/2) * M.calc(freq, &Enum.min_by/2)
end)
1997414

Part 2

defmodule M do
  defp freq_bit(li, max_fn) do
    li
    |> Enum.frequencies()
    |> max_fn.()
    |> then(fn r -> elem(r, 0) end)
  end

  def filter(li, position, max_fn) do
    if length(li) == 1 do
      li
    else
      filter(do_filter(li, position, max_fn), position + 1, max_fn)
    end
  end

  defp do_filter(li, position, max_fn) do
    li
    |> Enum.zip()
    |> Enum.at(position)
    |> Tuple.to_list()
    |> freq_bit(max_fn)
    |> then(fn bit ->
      Enum.filter(li, fn l -> Enum.at(l, position) == bit end)
    end)
  end

  defp max(li) do
    Enum.max_by(
      li,
      fn r -> elem(r, 1) end,
      fn x, y -> x > y end
    )
  end

  defp min(li) do
    Enum.min_by(
      li,
      fn r -> elem(r, 1) end,
      fn x, y -> x <= y end
    )
  end

  def oxygen(li) do
    li
    |> filter(0, &amp;max/1)
    |> Enum.at(0)
    |> List.to_string()
    |> String.to_integer(2)
  end

  def co2(li) do
    li
    |> filter(0, &amp;min/1)
    |> Enum.at(0)
    |> List.to_string()
    |> String.to_integer(2)
  end
end

Kino.Input.read(input)
|> String.split()
|> Enum.map(&amp;String.to_charlist/1)
|> then(&amp;(M.oxygen(&amp;1) * M.co2(&amp;1)))
1032597