Day 4: Repose Record - Advent of Code 2018

I did the Advent of Code 2018 day 4 challenge in Elixir! Parts one and two are as follows:

defmodule Day4_1 do
  # 1518-11-01 00:00
  @log_info ~r/\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.*)/
  @guard_entry ~r/Guard #(\d+) begins shift/

  def part1(input) do
    {_, _, guards} =
      input
      |> read_input()
      |> extract_logs()

    {guard_id, _time_asleep} = most_asleep(guards)
    {minute, _size} = get_most_asleep_minutes(guards[guard_id])
    minute * String.to_integer(guard_id)
  end

  def part2(input) do
    {_, _, guards} =
      input
      |> read_input()
      |> extract_logs()

    {guard_id, minute, _size} = most_times_asleep(guards)
    minute * String.to_integer(guard_id)
  end

  defp read_input(input) do
    input
    |> File.read!()
    |> String.split("\n", trim: true)
  end

  def extract_logs(lines) do
    lines
    |> Enum.sort()
    |> Enum.map(fn line ->
      [_year, _month, _day, _hour, minute, message] =
        Regex.run(@log_info, line, capture: :all_but_first)

      case message do
        "falls asleep" ->
          {:sleep, String.to_integer(minute)}

        "wakes up" ->
          {:wake, String.to_integer(minute)}

        _ ->
          [guard_id] = Regex.run(@guard_entry, message, capture: :all_but_first)
          {:guard, guard_id}
      end
    end)
    |> Enum.reduce({nil, nil, %{}}, fn log, {current_guard_id, last_minute, guards} ->
      case log do
        {:guard, guard_id} ->
          {guard_id, nil, Map.put_new(guards, guard_id, [])}

        {:sleep, minute} ->
          {current_guard_id, minute, guards}

        {:wake, minute} ->
          new_range = for min <- last_minute..(minute - 1), do: min
          {current_guard_id, nil, Map.update!(guards, current_guard_id, &(&1 ++ new_range))}
      end
    end)
  end

  defp most_asleep(guards) do
    Enum.reduce(guards, {nil, 0}, fn {guard_id, sleep_range}, {_, current_bigger_time} = acc ->
      time_asleep = length(sleep_range)

      if time_asleep > current_bigger_time do
        {guard_id, time_asleep}
      else
        acc
      end
    end)
  end

  defp most_times_asleep(guards) do
    Enum.reduce(guards, {nil, 0, 0}, fn {guard_id, asleep_range},
                                        {_current_guard, _minute, max_size} = acc ->
      {minute, size} = get_most_asleep_minutes(asleep_range)

      if size > max_size do
        {guard_id, minute, size}
      else
        acc
      end
    end)
  end

  defp get_minutes_of(guard_intervals) do
    {asleep_range, []} =
      guard_intervals
      |> Enum.reduce({[], []}, fn
        {datetime, _}, {range, []} ->
          {range, [datetime.minute]}

        {datetime, _}, {range, [asleep_time]} ->
          new_range = for min <- asleep_time..(datetime.minute - 1), do: min
          {[new_range | range], []}
      end)

    {minute, _size} = get_most_asleep_minutes(asleep_range)
    minute
  end

  defp get_most_asleep_minutes(asleep_range) do
    asleep_range
    |> Enum.group_by(& &1)
    |> Enum.reduce({nil, 0}, fn {minute, occurrences}, {_, times} = acc ->
      size = length(occurrences)

      if size > times do
        {minute, size}
      else
        acc
      end
    end)
  end
end

# :aoc2018 |> :code.priv_dir() |> Path.join("day4.txt") |> Day4_1.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day4.txt") |> Day4_1.part2()

 

Simon Escobar Benitez
Author

Simon Escobar Benitez

Colombian Software Engineer (Erlang Solutions)

ARTICLES: 8

Day 11: Chronal Charge - Advent of Code 2018

I did the Advent of Code 2018 day 11 challenge in Elixir! Parts one and two are as follows:

READ MORE

Day 10: The Stars Align - Advent of Code 2018

I did the Advent of Code 2018 day 10 challenge in Elixir! Parts one and two are as follows:

READ MORE

Day 7: The Sum of Its Parts - Advent of Code 2018

I did the Advent of Code 2018 day 7 challenge in Elixir! Parts one and two are as follows:

READ MORE

Day 6: Chronal Coordinates - Advent of Code 2018

I did the Advent of Code 2018 day 6 challenge in Elixir! Parts one and two are as follows:

READ MORE

Day 5: Alchemical Reduction - Advent of Code 2018

I did the Advent of Code 2018 day 5 challenge in Elixir! Parts one and two are as follows:

READ MORE

Day 3: No matter how you slice it - Advent of Code 2018

I did the Advent of Code 2018 day 3 challenge in Elixir! Parts one and two are as follows:

READ MORE

Day 2: Inventory Management System - Advent of Code 2018

I did the Advent of Code 2018 day 2 challenge in Elixir! Parts one and two are as follows:

READ MORE

Day 1: Chronal Calibration - Advent of Code 2018

Advent of Code 2018 - Day 1 solution in Elixir! #AdventOfBEAM

READ MORE