Powered by AppSignal & Oban Pro

Advent of code day 03

2021/livebooks/day-03.livemd

Advent of code day 03

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

Setup input

example = Kino.Input.textarea("Please paste your input example:")
input = Kino.Input.textarea("Please paste your real input:")

Helpers

defmodule CharFreq do
  def most_repeated_char_at_index(strings, index) when is_list(strings) and index >= 0 do
    characters_at_index = Enum.map(strings, &String.at(&1, index))
    char_counts = Enum.frequencies(characters_at_index)

    case Enum.max_by(char_counts, fn {_char, count} -> count end, &>/2) do
      {char, count} -> {char, count}
    end
  end

  def less_repeated_char_at_index(strings, index) when is_list(strings) and index >= 0 do
    characters_at_index = Enum.map(strings, &String.at(&1, index))
    char_counts = Enum.frequencies(characters_at_index)

    case Enum.min_by(char_counts, fn {_char, count} -> count end) do
      {char, count} -> {char, count}
    end
  end
end

Part 01

strings =
  input
  |> Kino.Input.read()
  |> String.split("\n")

most =
  for index <- 0..(String.length(Enum.at(strings, 0)) - 1) do
    {char, _count} = CharFreq.most_repeated_char_at_index(strings, index)
    char
  end

less =
  for index <- 0..(String.length(Enum.at(strings, 0)) - 1) do
    {char, _count} = CharFreq.less_repeated_char_at_index(strings, index)
    char
  end

most = most |> Enum.join("") |> String.to_integer(2)
less = less |> Enum.join("") |> String.to_integer(2)
most * less

Part 02

strings =
  input
  |> Kino.Input.read()
  |> String.split("\n")

most =
  for index <- 0..(String.length(Enum.at(strings, 0)) - 1) do
    {char, _count} = CharFreq.most_repeated_char_at_index(strings, index)
    char
  end

less =
  for index <- 0..(String.length(Enum.at(strings, 0)) - 1) do
    {char, _count} = CharFreq.less_repeated_char_at_index(strings, index)
    char
  end

oxygen =
  Enum.reduce_while(most |> Enum.with_index(), strings, fn {_char, idx}, acc ->
    {c, _count} = CharFreq.most_repeated_char_at_index(acc, idx)

    if length(acc) == 1 do
      {:halt, acc}
    else
      {:cont,
       Enum.filter(acc, fn el ->
         String.at(el, idx) == c
       end)}
    end
  end)
  |> List.first()
  |> String.to_integer(2)

co2 =
  Enum.reduce_while(most |> Enum.with_index(), strings, fn {_char, idx}, acc ->
    {c, _count} = CharFreq.less_repeated_char_at_index(acc, idx)

    if length(acc) == 1 do
      {:halt, acc}
    else
      {:cont,
       Enum.filter(acc, fn el ->
         String.at(el, idx) == c
       end)}
    end
  end)
  |> List.first()
  |> String.to_integer(2)

co2 * oxygen