Advent Of Code 2022 - Day 4

All my answers look the same :sob:

I thought about using a regex to extract the digits as I see others did with success, but I have a deeply embedded habit of strictly enforcing formatting rules for input like this (although I note @egze’s use does appear to enforce them without too much pain). Since there are a known quantity of sections though in a real case I would probably insist the format be changed to use leading zeros :smile:

Yea, MapSet all the way on this one :metal:

defmodule ExAOC2022.Day4 do
  @input "./lib/day4_input.txt"

  def puzzle1() do
    @input
    |> file_by_line()
    |> Enum.map(&line_to_elfarea/1)
    |> Enum.map(&subset?/1)
    |> Enum.reject(& !&1)
    |> length()
  end

  def puzzle2() do
    @input
    |> file_by_line()
    |> Enum.map(&line_to_elfarea/1)
    |> Enum.map(&intersect?/1)
    |> Enum.reject(& !&1)
    |> length()
  end

  defp line_to_elfarea(line) do
    line
    |> String.split(",")
    |> IO.inspect()
    |> Enum.map(&to_map_set/1)
  end

  defp to_map_set(area_str) do
    [first, last] = String.split(area_str, "-")

    Range.new(String.to_integer(first), String.to_integer(last))
    |> Enum.to_list
    |> MapSet.new()
  end

  defp subset?([one, two]) do
    MapSet.subset?(one, two) || MapSet.subset?(two, one)
  end

  defp intersect?([one, two]) do
    MapSet.size(MapSet.intersection(one, two)) > 0
  end

  defp file_by_line(file) do
    file
    |> File.read!()
    |> String.split(~r/\R/, trim: true)
  end
end

simple Elixir, using MapSet.subset? and MapSet.disjoint?, both questions at the same time

File.stream!("input")
|> Enum.reduce({0,0}, fn line, {acc_part1, acc_part2} ->
    [s1, e1, s2, e2] = line
      |> String.split(~r/\D/, trim: true)
      |> Enum.map(&String.to_integer/1)
    {m1, m2} = {MapSet.new(s1..e1), MapSet.new(s2..e2)}
    {
      acc_part1 + (if MapSet.subset?(m1,m2) || MapSet.subset?(m2,m1), do: 1, else: 0),
      acc_part2 + (if MapSet.disjoint?(m1,m2), do: 0, else: 1),
    }
end)
|> IO.inspect()

I went with a recursive solution for practice

defmodule Advent.Day4 do
  def getInput() do
    File.read!("inputs/day-4-input.txt")
    |> String.split("\n")
    |> Enum.map(fn line ->
      line
      |> String.split(",")
      |> Enum.map(fn orders ->
        orders
        |> String.split("-")
        |> Enum.map(&String.to_integer/1)
      end)
    end)
  end

  def score(x), do: if x, do: 1, else: 0

  def contains?([[a, b], [x, y]]) do
    (a >= x and b <= y) or (a <= x and b >= y)
  end

  def containing([]), do: 0
  def containing([pair | rest]) do
    score(contains? pair) + containing rest
  end

  def solution1() do
    getInput() |> containing
  end

  def overlaps?([[a, b], [x, y]]) do
    (b >= x and a <= y) or (y >= a and x <= b)
  end

  def overlapping([]), do: 0
  def overlapping([pair | rest]) do
    score(overlaps? pair) + overlapping rest
  end

  def solution2() do
    getInput() |> overlapping
  end
end

IO.puts Advent.Day4.solution1

IO.puts Advent.Day4.solution2

I decided to look into Regex, which I have never used before in Elixir. Here’s what I came up with, I don’t really like the part where I’m converting the strings to integers since this involves going through nested lists. I would have liked to do this somehow within Regex.scan/3, but I don’t know how. Maybe someone knows if it’s possible?

I’m happy with everything else. Especially since doing part 2 simply meant turning the and into or for the guard clauses in the Enum.reduce/3.