From ef3788fe91d2d82db737b324d6448da03d01a544 Mon Sep 17 00:00:00 2001
From: sloane <1699281+sloanelybutsurely@users.noreply.github.com>
Date: Tue, 5 Dec 2023 09:03:54 -0500
Subject: [PATCH] solve 2023 5.1

---
 2023/README.md     |  3 ++-
 2023/lib/2023/5.ex | 65 ++++++++++++++++++++++++++++++++++++++++++++++
 README.md          |  2 +-
 3 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100644 2023/lib/2023/5.ex

diff --git a/2023/README.md b/2023/README.md
index 67280f7..c988051 100644
--- a/2023/README.md
+++ b/2023/README.md
@@ -3,7 +3,7 @@
 |  S  |  M  |  T  |  W  |  T  |  F  |  S  |
 | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
 |     |     |     |     |     | [1] | [2] |
-| [3] | [4] |  5  |  6  |  7  |  8  |  9  |
+| [3] | [4] | [5] |  6  |  7  |  8  |  9  |
 | 10  | 11  | 12  | 13  | 14  | 15  | 16  |
 | 17  | 18  | 19  | 20  | 21  | 22  | 23  |
 | 24  | 25  |     |     |     |     |     |
@@ -13,3 +13,4 @@
 [2]: ./lib/2023/2.ex
 [3]: ./lib/2023/3.ex
 [4]: ./lib/2023/4.ex
+[5]: ./lib/2023/5.ex
diff --git a/2023/lib/2023/5.ex b/2023/lib/2023/5.ex
new file mode 100644
index 0000000..e8aa974
--- /dev/null
+++ b/2023/lib/2023/5.ex
@@ -0,0 +1,65 @@
+import AOC
+
+aoc 2023, 5 do
+  def p1(input) do
+    {seeds, maps} = read_input(input)
+
+    seeds
+    |> Enum.map(&traverse_maps(maps, &1))
+    |> Enum.min()
+  end
+
+  def p2(_input) do
+  end
+
+  def traverse_maps(maps, start) do
+    Enum.reduce(maps, start, &traverse_map/2)
+  end
+
+  def traverse_map(ranges_and_deltas, start) do
+    case Enum.find(ranges_and_deltas, fn {range, _} -> start in range end) do
+      {_, delta} -> start - delta
+      nil -> start
+    end
+  end
+
+  def read_input(input) do
+    ["seeds: " <> seeds_str, _ | map_strs] = String.split(input, "\n")
+
+    map_chunks =
+      map_strs
+      |> chunk_by_removing("")
+      |> Enum.map(&Enum.drop(&1, 1))
+      |> map_map(&to_integer_list/1)
+      |> map_map(&to_range_and_delta/1)
+
+    {to_integer_list(seeds_str), map_chunks}
+  end
+
+  def chunk_by_removing(enum, pattern) do
+    Enum.chunk_while(
+      enum,
+      [],
+      fn
+        ^pattern, acc -> {:cont, Enum.reverse(acc), []}
+        elem, acc -> {:cont, [elem | acc]}
+      end,
+      &{:cont, Enum.reverse(&1), []}
+    )
+  end
+
+  def to_integer_list(str) do
+    str
+    |> String.split()
+    |> Enum.map(&String.to_integer/1)
+  end
+
+  def to_range_and_delta([dest_start, source_start, len]) do
+    source_range = source_start..(source_start + len)
+    delta = source_start - dest_start
+
+    {source_range, delta}
+  end
+
+  def map_map(enum_of_enums, fun), do: Enum.map(enum_of_enums, fn enum -> Enum.map(enum, fun) end)
+end
diff --git a/README.md b/README.md
index eaf8cd2..e770f5f 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
 1. [2020] **17/50** 🌟
 1. [2021] **43/50** 🌟
 1. [2022] **14/50** 🌟
-1. [2023] **8/50** 🌟
+1. [2023] **9/50** 🌟
 
 [2015]: ./2015
 [2017]: ./2017