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

2021 Day 3

2021/day_3.livemd

2021 Day 3

Mix.install([
  {:kino, "~> 0.6.1"},
  {:kino_vega_lite, "~> 0.1.1"}
])

alias VegaLite, as: Vl

Input

raw_input = Kino.Input.textarea("Problem Input")

Parse

input =
  Kino.Input.read(raw_input)
  |> String.trim()
  |> String.split("\n")
  |> Enum.map(&String.split(&1, "", trim: true))

Helpers

defmodule Helpers do
  def transpose(matrix) do
    matrix
    |> List.zip()
    |> Enum.map(&Tuple.to_list/1)
  end
end

Helpers.transpose([
  [1, 2, 3],
  [4, 5, 6]
])

Part 1

defmodule Part1 do
  def calculate_gamma(input) do
    input
    |> Helpers.transpose()
    |> Enum.map(&Enum.frequencies/1)
    |> Enum.map(fn %{"0" => zeros, "1" => ones} ->
      if zeros > ones do
        "0"
      else
        "1"
      end
    end)
    |> Enum.join()
  end

  def calculate_epsilon("1"), do: "0"
  def calculate_epsilon("0"), do: "1"

  def calculate_epsilon(gamma) do
    gamma
    |> String.split("", trim: true)
    |> Enum.map(&calculate_epsilon/1)
    |> Enum.join()
  end
end

gamma = Part1.calculate_gamma(input)
epsilon = Part1.calculate_epsilon(gamma)
String.to_integer(gamma, 2) * String.to_integer(epsilon, 2)

Part 2

defmodule Part2 do
  def find_oxygen(input), do: find_oxygen(input, 0)

  def find_oxygen(input, column) do
    most_popular = most_popular_in_column(input, column, & Helpers.transpose()
    |> Enum.map(&Enum.frequencies/1)
    |> Enum.map(fn freqs ->
      if comparator.(Map.get(freqs, "0", 0), Map.get(freqs, "1", 0)) do
        "0"
      else
        "1"
      end
    end)
    |> Enum.at(column)
  end
end

Part2.find_oxygen(input)
Part2.most_popular_in_column([["1", "1"], ["0", "0"]], 0, &