From da610160ea1ce920ddcf36626ba70d31ca056f29 Mon Sep 17 00:00:00 2001
From: Sloane Perrault <sloane.perrault@gmail.com>
Date: Wed, 21 Sep 2022 09:19:54 -0400
Subject: [PATCH] 2021 22 pt 1

---
 2021/lib/2021/22.ex | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 2021/lib/2021/22.ex

diff --git a/2021/lib/2021/22.ex b/2021/lib/2021/22.ex
new file mode 100644
index 0000000..25d7039
--- /dev/null
+++ b/2021/lib/2021/22.ex
@@ -0,0 +1,42 @@
+import AOC
+
+aoc 2021, 22 do
+  def p1 do
+    input_cuboids()
+    |> Enum.filter(&within_range(-50..50, &1))
+    |> Enum.reduce(MapSet.new(), fn
+      {:on, ranges}, acc -> MapSet.union(acc, make_set(ranges))
+      {:off, ranges}, acc -> MapSet.difference(acc, make_set(ranges))
+    end)
+    |> MapSet.size()
+  end
+
+  def p2 do
+  end
+
+  def make_set({xs, ys, zs}) do
+    for x <- xs, y <- ys, z <- zs, into: MapSet.new(), do: {x, y, z}
+  end
+
+  def within_range(bounds, {tag, ranges}) when tag in ~w[on off]a, do: within_range(bounds, ranges)
+  def within_range(bounds, {x, y, z}), do:
+    within_range(bounds, x) and within_range(bounds, y) and within_range(bounds, z)
+  def within_range(bs..be, s..e), do: bs <= s and e <= be
+
+  def parse_cuboid_ranges(str) do
+    ~r/x=(-?\d+)..(-?\d+),y=(-?\d+)..(-?\d+),z=(-?\d+)..(-?\d+)/
+      |> Regex.run(str, capture: :all_but_first)
+      |> Enum.map(&String.to_integer/1)
+      |> Enum.chunk_every(2)
+      |> Enum.map(&apply(Range, :new, &1))
+      |> List.to_tuple()
+  end
+
+  def input_cuboids() do
+    input_stream()
+    |> Enum.map(fn
+      "on " <> rest -> {:on, parse_cuboid_ranges(rest)}
+      "off " <> rest -> {:off, parse_cuboid_ranges(rest)}
+    end)
+  end
+end