From d06708a9a2c0507f3a5581a593cc6435d767ed5e Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Wed, 5 Dec 2018 02:12:19 -0500 Subject: oops, forgot to push day 4; here's day 5 too --- day4.exs | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 day4.exs (limited to 'day4.exs') 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()) -- cgit 1.4.1