Powered by AppSignal & Oban Pro

Day 3: Binary Diagnostic

2021/day_03_binary_diagnostic.livemd

Day 3: Binary Diagnostic

Mix.install([:kino])

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

Setup

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

Part 1

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

Solve: Part 1

separator = Enum.count(inputs) / 2

[gamma_rate, epsilon_rate] =
  inputs
  |> Enum.zip_with(& &1)
  |> Enum.map(fn list ->
    case Enum.count(list, &(&1 == "1")) > separator do
      true -> ["1", "0"]
      false -> ["0", "1"]
    end
  end)
  |> Enum.zip_with(& &1)
  |> Enum.map(fn list ->
    list
    |> Enum.join()
    |> Integer.parse(2)
    |> elem(0)
  end)

_answer = gamma_rate * epsilon_rate

Part 2

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

Solve: Part 2

defmodule Part2.Solver do
  def solve(inputs, mode) do
    {result, _} =
      inputs
      |> do_solve(0, mode)
      |> Enum.join()
      |> Integer.parse(2)

    result
  end

  def do_solve([report], _, _) do
    report
  end

  def do_solve(reports, index, mode) do
    grouped_reports =
      reports
      |> Enum.group_by(fn report ->
        report |> Enum.at(index)
      end)

    reports0 = grouped_reports |> Map.get("0", [])
    reports1 = grouped_reports |> Map.get("1", [])

    op_compare =
      case mode do
        :oxygen_generator_rating -> &Kernel.>/2
        :co2_scrubber_rating -> &Kernel.<=/2
      end

    filtered_reports =
      case op_compare.(Enum.count(reports0), Enum.count(reports1)) do
        true -> reports0
        false -> reports1
      end

    do_solve(filtered_reports, index + 1, mode)
  end
end

oxygen_generator_rating = Part2.Solver.solve(inputs, :oxygen_generator_rating)
co2_scrubber_rating = Part2.Solver.solve(inputs, :co2_scrubber_rating)

_answer = oxygen_generator_rating * co2_scrubber_rating