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

Day 03

day-03.livemd

Day 03

Setup

Mix.install([
  {:kino, "~> 0.4.1"}
])
input = Kino.Input.textarea("Please enter your Input")
input =
  input
  |> Kino.Input.read()
  |> String.split()
  |> Enum.map(&String.graphemes/1)

Part 1

frequencies =
  input
  |> Enum.zip()
  |> Enum.map(&Tuple.to_list/1)
  |> Enum.map(&Enum.frequencies/1)
  |> Enum.reduce([], fn
    %{"0" => a, "1" => b}, acc when a > b -> [{0, 1} | acc]
    _, acc -> [{1, 0} | acc]
  end)
  |> Enum.reverse()

low =
  frequencies
  |> Enum.map(&elem(&1, 0))
  |> Enum.join("")
  |> String.to_integer(2)

high =
  frequencies
  |> Enum.map(&elem(&1, 1))
  |> Enum.join("")
  |> String.to_integer(2)

low * high

Part 2

defmodule Part2 do
  def most_common_in_tuple(tuple) do
    case tuple do
      %{"0" => a, "1" => b} when a > b -> "0"
      _ -> "1"
    end
  end

  def most_common_at_position(list, position) do
    list
    |> Enum.map(&Enum.fetch!(&1, position))
    |> Enum.frequencies()
    |> most_common_in_tuple()
  end

  def most_common(list, position \\ 0)
  def most_common(list, _) when length(list) == 1, do: Enum.fetch!(list, 0)

  def most_common(list, position) do
    list
    |> Enum.filter(fn number ->
      Enum.fetch!(number, position) == most_common_at_position(list, position)
    end)
    |> most_common(position + 1)
  end

  def least_common(list, position \\ 0)
  def least_common(list, _) when length(list) == 1, do: Enum.fetch!(list, 0)

  def least_common(list, position) do
    list
    |> Enum.filter(fn number ->
      Enum.fetch!(number, position) != most_common_at_position(list, position)
    end)
    |> least_common(position + 1)
  end
end

largest =
  input
  |> Part2.most_common()
  |> Enum.join("")
  |> String.to_integer(2)

smallest =
  input
  |> Part2.least_common()
  |> Enum.join("")
  |> String.to_integer(2)

smallest * largest