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

AOC 2022 - Day 04

aoc2022/day04.livemd

AOC 2022 - Day 04

Mix.install([
  {:kino_aoc, "~> 0.1"}
])

AOC Helper

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2022", "4", System.fetch_env!("LB_AOC_SESSION"))

Part 1

Code

defmodule PartOne do
  def sections(value) do
    [s, e] = value |> String.split("-") |> Enum.map(&String.to_integer/1)

    s..e |> Enum.to_list() |> MapSet.new()
  end

  def subset?(section1, section2),
    do: MapSet.subset?(section1, section2) || MapSet.subset?(section2, section1)

  def solve(input) do
    IO.puts("--- Part One ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    input
    |> String.split("\n")
    |> Enum.reduce(0, fn pairing, count ->
      [assign1, assign2] = pairing |> String.trim() |> String.split(",")
      section1 = sections(assign1)
      section2 = sections(assign2)

      if subset?(section1, section2), do: count + 1, else: count
    end)
  end
end

Test

ExUnit.start(autorun: false)

defmodule PartOneTest do
  use ExUnit.Case, async: true
  import PartOne

  @input "2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8"
  @expected 2

  test "part one" do
    actual = run(@input)
    assert actual == @expected
  end
end

ExUnit.run()

Solution

PartOne.solve(puzzle_input)

Part 2

Code

defmodule PartTwo do
  def sections(value) do
    [s, e] = value |> String.split("-") |> Enum.map(&String.to_integer/1)

    s..e |> Enum.to_list() |> MapSet.new()
  end

  def overlap?(section1, section2) do
    MapSet.intersection(section1, section2)
    |> MapSet.to_list()
    |> Enum.empty?()
    |> Kernel.not()
  end

  def solve(input) do
    IO.puts("--- Part Two ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    input
    |> String.split("\n")
    |> Enum.reduce(0, fn pairing, count ->
      [assign1, assign2] = pairing |> String.trim() |> String.split(",")
      section1 = sections(assign1)
      section2 = sections(assign2)

      if overlap?(section1, section2), do: count + 1, else: count
    end)
  end
end

Test

ExUnit.start(autorun: false)

defmodule PartTwoTest do
  use ExUnit.Case, async: true
  import PartTwo

  @input "2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8"
  @expected 4

  test "part two" do
    actual = run(@input)
    assert actual == @expected
  end
end

ExUnit.run()

Solution

PartTwo.solve(puzzle_input)