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