Powered by AppSignal & Oban Pro

Advent of Code 2021 - Day 3

advent-of-code/2021/day03.livemd

Advent of Code 2021 - Day 3

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

Instructions

https://adventofcode.com/2021/day/3

Get input

Paste the test input from the Day 3 instructions, your own input from Advent of Code, or copy from sdball 2021 Advent of Code Day 3 input

input = Kino.Input.textarea("Please paste your input:")
input = input |> Kino.Input.read() |> String.split()

Part 1

[sample | _] = input
bit_count = sample |> String.length()

frequencies =
  for x <- 0..(bit_count - 1) do
    input
    |> Enum.map(fn number ->
      String.at(number, x) |> String.to_integer()
    end)
  end
  |> Enum.map(fn bits ->
    bits |> Enum.frequencies()
  end)

gamma =
  frequencies
  |> Enum.map(fn freq ->
    if freq[0] < freq[1], do: 1, else: 0
  end)
  |> Enum.join()
  |> String.to_integer(2)

epsilon =
  frequencies
  |> Enum.map(fn freq ->
    if freq[0] < freq[1], do: 0, else: 1
  end)
  |> Enum.join()
  |> String.to_integer(2)

power_consumption = gamma * epsilon

Part 2

defmodule LifeSupport do
  def oxygen_generator_rating(report) do
    oxygen_generator_rating(report, 0) |> String.to_integer(2)
  end

  def oxygen_generator_rating([result], _position), do: result

  def oxygen_generator_rating(report, position) do
    most_frequent = most_frequent_at(report, position) |> Integer.to_string()

    report
    |> Enum.filter(fn number -> String.at(number, position) == most_frequent end)
    |> oxygen_generator_rating(position + 1)
  end

  def co2_scrubber_rating(report) do
    co2_scrubber_rating(report, 0) |> String.to_integer(2)
  end

  def co2_scrubber_rating([result], _position), do: result

  def co2_scrubber_rating(report, position) do
    most_frequent = most_frequent_at(report, position) |> Integer.to_string()

    report
    |> Enum.filter(fn number -> String.at(number, position) != most_frequent end)
    |> co2_scrubber_rating(position + 1)
  end

  defp most_frequent_at(list, position) do
    freq = frequencies(list, position)
    if freq[0] <= freq[1], do: 1, else: 0
  end

  defp frequencies(report, position) do
    report
    |> Enum.map(fn number ->
      String.at(number, position) |> String.to_integer()
    end)
    |> Enum.frequencies()
  end
end
LifeSupport.oxygen_generator_rating(input) * LifeSupport.co2_scrubber_rating(input)

Scratch

frequencies = [
  %{0 => 5, 1 => 7},
  %{0 => 7, 1 => 5},
  %{0 => 4, 1 => 8},
  %{0 => 5, 1 => 7},
  %{0 => 7, 1 => 5}
]

gamma_digits =
  frequencies
  |> Enum.map(fn freq ->
    if freq[0] < freq[1], do: 1, else: 0
  end)
gamma_digits
|> Integer.undigits(2)