### re: AoC Day 4: Repose Record VIEW POST

Didn't really have much time to do the challenges today, but yeah, whenever you did the first three days it's hard to skip one.

So here are my solutions in Elixir. Some function returns are a bit messy, but it does what it needs to do. The basic idea is that all lines are first parsed into a map with guards, where each guard is the key for another map containing the minutes and the number of times the guard was asleep during that minute.

Having that basic map makes the calculations for both strategies relatively easy.

Common:

defmodule AoC.DayFour.Common do
@line_regex ~r/$(.*)$ (.*)/
@date_format "{YYYY}-{M}-{D} {h24}:{m}"

path
|> File.stream!()
|> Stream.map(&String.trim_trailing/1)
|> Enum.to_list()
|> Enum.sort()
|> Enum.map(fn x ->
[datetime, log] = Regex.run(@line_regex, x, capture: :all_but_first)
{:ok, datetime} = Timex.parse(datetime, @date_format)
%{datetime: datetime, log: log}
end)
end

def calculate_guard_minutes(input, map \\ %{}, current_guard \\ "", last_minute \\ 0)

def calculate_guard_minutes([line | rest], map, current_guard, last_minute) do
case line.log do
"falls asleep" ->
calculate_guard_minutes(rest, map, current_guard, line.datetime.minute)

"wakes up" ->
map = Map.put_new(map, current_guard, %{})
guard = Map.get(map, current_guard)

guard =
Enum.reduce(last_minute..(line.datetime.minute - 1), guard, fn x, acc ->
Map.update(acc, x, 1, &(&1 + 1))
end)

map = Map.put(map, current_guard, guard)
calculate_guard_minutes(rest, map, current_guard, line.datetime.minute)

_ ->
[new_guard] =
Regex.run(~r/^Guard #(\d+) begins shift\$/, line.log, capture: :all_but_first)

calculate_guard_minutes(rest, map, new_guard, 0)
end
end

def calculate_guard_minutes([], map, _current_guard, _last_minute) do
map
end
end


Part one:

defmodule AoC.DayFour.PartOne do
alias AoC.DayFour.Common

def main() do
"lib/day4/input.txt"
|> Common.calculate_guard_minutes()
|> get_sleepiest_guard()
|> get_sleepiest_minute()
|> calculate_result()
end

defp calculate_result({guard, minute}) do
guard * minute
end

defp get_sleepiest_minute(map) do
{_, {guard, minutes}} = map

{sleepiest_minute, _} =
# Format: {guard, minutes_slept}
Enum.reduce(minutes, {0, 0}, fn {current_minute, count}, {highest_minute, highest_count} ->
if count > highest_count,
do: {current_minute, count},
else: {highest_minute, highest_count}
end)

{String.to_integer(guard), sleepiest_minute}
end

defp get_sleepiest_guard(map) do
# Format: {minutes_slept, {guard, minutes}}
Enum.reduce(map, {0, {0, %{}}}, fn {guard, minutes}, sleepiest_guard ->
minutes_slept = Enum.reduce(minutes, 0, fn {_, count}, acc -> acc + count end)
{current_sleep_minutes, _} = sleepiest_guard

if minutes_slept > current_sleep_minutes,
do: {minutes_slept, {guard, minutes}},
else: sleepiest_guard
end)
end
end


Part two:

defmodule AoC.DayFour.PartTwo do
alias AoC.DayFour.Common

def main() do
"lib/day4/input.txt"
|> Common.calculate_guard_minutes()
|> get_sleepiest_guard()
|> calculate_result()
end

defp calculate_result({guard, minute}) do
guard * minute
end

defp get_sleepiest_guard(map) do
# Format: {guard, minute, count}
{guard, minute, _} =
Enum.reduce(map, {0, 0, 0}, fn {guard, minutes}, sleepiest_guard ->
# Format: {minute, count}
{minute, count} =
Enum.reduce(minutes, {0, 0}, fn {minute, count}, {current_minute, highest_count} ->
if count > highest_count, do: {minute, count}, else: {current_minute, highest_count}
end)

{_, _, current_count} = sleepiest_guard

if count > current_count,
do: {String.to_integer(guard), minute, count},
else: sleepiest_guard
end)

{guard, minute}
end
end

code of conduct - report abuse