Powered by AppSignal & Oban Pro

Day22

2021/day22.livemd

Day22

Untitled

data =
  "input"
  |> IO.getn(1_000_000)
  |> String.trim()
  |> String.split(["\r\n", "\n"], trim: true)
  |> Enum.map(fn line ->
    line
    |> String.split()
    |> then(fn [on_off, coords] ->
      coords
      |> String.replace(~r/x=|y=|z=/, "")
      |> String.split(",")
      |> Enum.map(&Code.eval_string/1)
      |> Enum.map(&elem(&1, 0))
      |> then(&{on_off == "on", &1})
    end)
  end)
defmodule D22 do
  def remove(
        [x1min..x1max, y1min..y1max, z1min..z1max] = c1,
        [x2min..x2max, y2min..y2max, z2min..z2max] = c2
      ) do
    if [c1, c2]
       |> Enum.zip()
       |> Enum.any?(fn {left, right} -> Range.disjoint?(left, right) end) do
      [c1]
    else
      [
        [x1min..x1max//1, y1min..y1max//1, z1min..(z2min - 1)//1],
        [x1min..x1max//1, y1min..y1max//1, (z2max + 1)..z1max//1],
        [x1min..(x2min - 1)//1, y1min..y1max//1, max(z1min, z2min)..min(z1max, z2max)//1],
        [(x2max + 1)..x1max//1, y1min..y1max//1, max(z1min, z2min)..min(z1max, z2max)//1],
        [
          max(x1min, x2min)..min(x1max, x2max)//1,
          y1min..(y2min - 1)//1,
          max(z1min, z2min)..min(z1max, z2max)//1
        ],
        [
          max(x1min, x2min)..min(x1max, x2max)//1,
          (y2max + 1)..y1max//1,
          max(z1min, z2min)..min(z1max, z2max)//1
        ]
      ]
      |> Enum.reject(fn c -> Enum.any?(c, &(Range.size(&1) == 0)) end)
    end
  end

  def limit(a..b) do
    if Range.disjoint?(a..b, -50..50) do
      1..0//1
    else
      max(-50, a)..min(b, 50)
    end
  end

  def solve(on, [], _) do
    on
    |> Enum.map(fn c ->
      c
      |> Enum.map(&Range.size/1)
      |> Enum.product()
    end)
    |> Enum.sum()
  end

  def solve(on, [{add?, c2} | instructions], limit) do
    c2 = Enum.map(c2, limit)

    Enum.flat_map(on, fn c1 ->
      remove(c1, c2)
    end)
    |> then(fn on ->
      if add? do
        [c2 | on]
      else
        on
      end
    end)
    |> solve(instructions, limit)
  end
end

P1

D22.solve([], data, &D22.limit/1)

P2

D22.solve([], data, & &1)