Advent of Code 2020 in Elixir - Day 15

Rambunctious Recitation

defmodule Aoc2020.Day15 do
  @moduledoc "Rambunctious Recitation"

  def run(), do: :timer.tc(fn -> part_2() end)

  def part_1(), do: find_nth_number(2020)
  def part_2(), do: find_nth_number(30_000_000)

  def find_nth_number(num) do
    input = parse_input()
    turns = Stream.iterate(1, &(&1 + 1))
    initial_turns = Stream.zip(input, turns) |> Enum.take(length(input))
    acc = Enum.into(Enum.take(initial_turns, length(initial_turns) - 1), %{})

    Stream.concat(initial_turns, Stream.unfold({List.last(initial_turns), acc}, &next_number/1))
    |> Enum.take(num)
    |> List.last()
    |> (fn {v, _} -> v end).()
  end

  def parse_input() do
    "19,0,5,1,10,13"
    |> String.split(",")
    |> Enum.map(&String.to_integer/1)
  end

  def next_number({{last_value, last_turn_num}, acc}) do
    current_turn_num = last_turn_num + 1

    case Map.fetch(acc, last_value) do
      {:ok, last_turn} ->
        age = last_turn_num - last_turn
        turn = {age, current_turn_num}
        {turn, {turn, Map.put(acc, last_value, last_turn_num)}}

      _ ->
        turn = {0, current_turn_num}
        {turn, {turn, Map.put(acc, last_value, last_turn_num)}}
    end
  end
end