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

Advent of Code 2022 - Day 4

aoc2022-04.livemd

Advent of Code 2022 - Day 4

Mix.install([
  {:req_aoc, github: "mcrumm/req_aoc", ref: "eef58c9"}
])

Puzzle description

Day 4: Camp Cleanup.

Solution

defmodule Part1 do
  # preflight:
  ## split string into lines (without break characters)
  def run(input) do
    input
    |> Stream.map(fn line ->
      {hr, tr} = to_range_pair(line)
      {MapSet.new(hr), MapSet.new(tr)}
    end)
    |> Stream.filter(fn {hms, tms} ->
      MapSet.subset?(hms, tms) or MapSet.subset?(tms, hms)
    end)
    |> Enum.count()
  end

  def to_range_pair(line) do
    [head, tail] = line |> String.split(",", parts: 2)
    [h1, h2] = head |> String.split("-", parts: 2) |> Enum.map(&String.to_integer/1)
    [t1, t2] = tail |> String.split("-", parts: 2) |> Enum.map(&String.to_integer/1)
    {h1..h2, t1..t2}
  end
end

defmodule Part2 do
  # preflight:
  ## split string into lines (without break characters)
  def run(input) do
    input
    |> Stream.map(fn line -> line |> Part1.to_range_pair() end)
    |> Stream.filter(fn {hr, tr} -> not Range.disjoint?(hr, tr) end)
    |> Enum.count()
  end
end

ExUnit.start(autorun: false)

defmodule Test do
  use ExUnit.Case, async: true
  @example_input ~s(
2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8
)

  @input System.fetch_env!("LB_AOC_SESSION") |> ReqAOC.fetch!({2022, 04}, max_retries: 0)

  test "to_range_pair/1" do
    assert @example_input
           |> to_lines()
           |> Enum.map(&Part1.to_range_pair/1) === [
             {2..4, 6..8},
             {2..3, 4..5},
             {5..7, 7..9},
             {2..8, 3..7},
             {6..6, 4..6},
             {2..6, 4..8}
           ]
  end

  test "part 1" do
    assert @example_input |> to_lines() |> Part1.run() === 2

    @input |> to_lines() |> Part1.run() |> dbg()
  end

  test "part 2" do
    assert @example_input |> to_lines() |> Part2.run() === 4

    @input |> to_lines() |> Part2.run() |> dbg()
  end

  @doc """
  Splits a string by newlines.
  """
  def to_lines(input) when is_binary(input) do
    input
    |> String.trim("\n")
    |> String.split("\n")
  end
end

ExUnit.configure(trace: true)
ExUnit.run()