about summary refs log tree commit diff
path: root/day4.exs
diff options
context:
space:
mode:
authorBen Harris <ben@tilde.team>2018-12-05 02:12:19 -0500
committerBen Harris <ben@tilde.team>2018-12-05 02:12:19 -0500
commitd06708a9a2c0507f3a5581a593cc6435d767ed5e (patch)
tree9c2dcf18cb5a0d6ab1bc48c3dbdf0dfbccf8da83 /day4.exs
parent1fb359f4831f23653c5517f6ef0d1dc0b607db4d (diff)
oops, forgot to push day 4; here's day 5 too HEAD master
Diffstat (limited to 'day4.exs')
-rw-r--r--day4.exs95
1 files changed, 95 insertions, 0 deletions
diff --git a/day4.exs b/day4.exs
new file mode 100644
index 0000000..afbedb0
--- /dev/null
+++ b/day4.exs
@@ -0,0 +1,95 @@
+defmodule Day4 do
+  def input() do
+    File.stream!("input/day4.in")
+    |> Stream.map(&String.trim/1)
+    |> Enum.sort()
+  end
+
+  def part1() do
+    {id, minute, _} =
+      input()
+      |> Enum.map(&parse_record_pattern/1)
+      |> Enum.reduce({%{}, [], []}, &stack_and_map/2)
+      |> elem(0)
+      |> Enum.max_by(fn {_k, v} ->
+        v.asleep
+        |> Enum.map(&Enum.sum/1)
+        |> Enum.sum()
+      end)
+      |> sleepiest_minute()
+
+    id * minute
+  end
+
+  def part2() do
+    {id, minute, _count} =
+      input()
+      |> Enum.map(&parse_record_pattern/1)
+      |> Enum.reduce({%{}, [], []}, &stack_and_map/2)
+      |> elem(0)
+      |> Enum.map(&sleepiest_minute/1)
+      |> Enum.max_by(fn {_id, _min, count} -> count end)
+
+    id * minute
+  end
+
+  defp sleepiest_minute({id, %{asleep: list_of_ranges}}) do
+    {minute, list} =
+      list_of_ranges
+      |> Enum.flat_map(& &1)
+      |> Enum.group_by(& &1)
+      |> Enum.max_by(fn {_k, v} -> length(v) end, fn -> {0, []} end)
+
+    {id, minute, length(list)}
+  end
+
+  def parse_record_pattern(string) do
+    <<
+      "[",
+      _date::binary-size(10),
+      " ",
+      _hour::binary-size(2),
+      ":",
+      minute::binary-size(2),
+      "] ",
+      action::binary
+    >> = string
+
+    %{
+      minute: String.to_integer(minute),
+      action: parse_action(action)
+    }
+  end
+
+  defp parse_action("Guard #" <> string) do
+    [id] = Regex.run(~r/\d+/, string)
+    {:guard, String.to_integer(id)}
+  end
+
+  defp parse_action("wakes up"), do: :wake_up
+  defp parse_action("falls asleep"), do: :sleep
+
+  def stack_and_map(%{action: {:guard, id}}, {map, awake_stack, asleep_stack}) do
+    {Map.put_new(map, id, %{slept: nil, asleep: []}), [id | awake_stack], asleep_stack}
+  end
+
+  def stack_and_map(
+        %{action: :sleep, minute: minute} = _record,
+        {map, [current_id | awake_stack], asleep_stack}
+      ) do
+    {put_in(map, [current_id, :slept], minute), awake_stack, [current_id | asleep_stack]}
+  end
+
+  def stack_and_map(
+        %{action: :wake_up, minute: minute} = _record,
+        {map, awake_stack, [current_id | asleep_stack]}
+      ) do
+    went_to_sleep = get_in(map, [current_id, :slept])
+
+    {update_in(map, [current_id, :asleep], &[went_to_sleep..(minute - 1) | &1]),
+     [current_id | awake_stack], asleep_stack}
+  end
+end
+
+IO.puts(Day4.part1())
+IO.puts(Day4.part2())