Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 14: Reindeer Olympics

elixir/day_14_reindeer_olympics.livemd

Day 14: Reindeer Olympics

Section

regex = ~r/(\w+) can fly (\d+) km\/s for (\d+) seconds, but then must rest for (\d+) seconds/

map =
  "Vixen can fly 8 km/s for 8 seconds, but then must rest for 53 seconds.
Blitzen can fly 13 km/s for 4 seconds, but then must rest for 49 seconds.
Rudolph can fly 20 km/s for 7 seconds, but then must rest for 132 seconds.
Cupid can fly 12 km/s for 4 seconds, but then must rest for 43 seconds.
Donner can fly 9 km/s for 5 seconds, but then must rest for 38 seconds.
Dasher can fly 10 km/s for 4 seconds, but then must rest for 37 seconds.
Comet can fly 3 km/s for 37 seconds, but then must rest for 76 seconds.
Prancer can fly 9 km/s for 12 seconds, but then must rest for 97 seconds.
Dancer can fly 37 km/s for 1 seconds, but then must rest for 36 seconds."
  # "Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds.
  # Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds."
  |> String.split("\n")
  |> Enum.map(fn line ->
    case Regex.run(regex, line, capture: :all_but_first) do
      [name, speed, active_time, rest_time] ->
        {name,
         %{
           speed: String.to_integer(speed),
           active_time: String.to_integer(active_time),
           rest_time: String.to_integer(rest_time)
         }}
    end
  end)
  |> Enum.into(%{})

result =
  Enum.reduce(0..2502, %{}, fn n, acc ->
    Enum.reduce(map, acc, fn {name, attrs}, acc_inner ->
      cycle_time = attrs.active_time + attrs.rest_time

      if rem(n, cycle_time) < attrs.active_time do
        Map.update(acc_inner, name, attrs.speed, &amp;(&amp;1 + attrs.speed))
      else
        acc_inner
      end
    end)
  end)

Enum.max_by(result, fn {_k, v} -> v end)
{"Donner", 2655}
result2 =
  Enum.reduce(0..2502, %{}, fn n, acc ->
    acc =
      Enum.reduce(map, acc, fn {name, attrs}, acc_inner ->
        cycle_time = attrs.active_time + attrs.rest_time

        if rem(n, cycle_time) < attrs.active_time do
          Map.update(acc_inner, name, {attrs.speed, 0}, fn {dist, points} ->
            {dist + attrs.speed, points}
          end)
        else
          acc_inner
        end
      end)

    max_dist = Enum.max_by(acc, fn {_k, {dist, _points}} -> dist end) |> elem(1) |> elem(0)

    largest_keys =
      Enum.filter(acc, fn {_key, {dist, _points}} -> dist == max_dist end)
      |> Enum.map(&amp;elem(&amp;1, 0))

    Enum.reduce(largest_keys, acc, fn key, inner_acc ->
      Map.update!(inner_acc, key, fn {dist, points} -> {dist, points + 1} end)
    end)
  end)

{name, {dist, points}} = Enum.max_by(result2, fn {_k, {_dist, points}} -> points end)
{name, points}
{"Vixen", 1059}