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

Day 8

livebook/8.livemd

Day 8

Part 1

input = File.stream!("8/input.txt")
# input = File.stream!("8/example.txt")
defmodule U do
  def parse(input) do
    {_, nodes} =
      Enum.reduce(input, {0, %{}}, fn line, {line_no, nodes} ->
        {_, nodes} = Enum.reduce(String.codepoints(line), {0, nodes}, fn char, {col, nodes} ->
          if Regex.match?(~r/\w/, char) do
            n = Map.get(nodes, char, [])
            {col + 1, Map.put(nodes, char, [{line_no, col} | n])}
          else
            {col + 1, nodes}
          end
        end)
        {line_no + 1, nodes}
      end)

    size =
      {(Enum.at(input, 0) |> String.codepoints() |> Enum.count()) - 1,
       input |> Enum.to_list() |> Enum.count()}

    {size, nodes}
  end
end
{size, nodes} = U.parse(input)
defmodule P1 do
  def antinodes({w, h}, nodes) do
    Enum.reduce(nodes, MapSet.new(), fn {_, nodes}, res ->
      Enum.reduce(nodes, res, fn {x1, y1} = n1, res ->
        Enum.reduce(nodes, res, fn {x2, y2} = n2, res ->
          if n1 != n2 do
            {x_diff, y_diff} = {x1 - x2, y1 - y2}

            {x_new, y_new} = {x1 + x_diff, y1 + y_diff}

            res =
              if x_new >= 0 &amp;&amp; x_new < w &amp;&amp; y_new >= 0 &amp;&amp; y_new < h do
                MapSet.put(res, {x_new, y_new})
              else
                res
              end

            {x_new, y_new} = {x2 - x_diff, y2 - y_diff}

            if x_new >= 0 &amp;&amp; x_new < w &amp;&amp; y_new >= 0 &amp;&amp; y_new < h do
              MapSet.put(res, {x_new, y_new})
            else
              res
            end
          else
            res
          end
        end)
      end)
    end)
  end
end
P1.antinodes(size, nodes) |> Enum.count

Part 2

defmodule P2 do
  def antinodes(size, nodes) do
    Enum.reduce(nodes, MapSet.new(), fn {_, nodes}, res ->
      Enum.reduce(nodes, res, fn {x1, y1} = n1, res ->
        Enum.reduce(nodes, res, fn {x2, y2} = n2, res ->
          if n1 != n2 do
            {x_diff, y_diff} = {x1 - x2, y1 - y2}

            res
            |> MapSet.put(n1)
            |> MapSet.put(n2)
            |> add_antinodes(size, n1, {x_diff, y_diff})
            |> add_antinodes(size, n2, {-x_diff, -y_diff})
          else
            res
          end
        end)
      end)
    end)
  end

  def add_antinodes(res, {w, h} = size, {x, y}, {x_diff, y_diff} = diff) do
    {x_new, y_new} = {x + x_diff, y + y_diff}

    if x_new >= 0 &amp;&amp; x_new < w &amp;&amp; y_new >= 0 &amp;&amp; y_new < h do
      MapSet.put(res, {x_new, y_new})
      |> add_antinodes(size, {x_new, y_new}, diff)
    else
      res
    end
  end
end
P2.antinodes(size, nodes) |> Enum.count