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

Day15

day15.livemd

Day15

Setup

Mix.install([
  {:kino, "~> 0.5.0"}
])
sample_text = Kino.Input.textarea("sample")
input_text = Kino.Input.textarea("input")
sample = Kino.Input.read(sample_text)
input = Kino.Input.read(input_text)
defmodule Game do
  defstruct last: nil, record: %{}, turn: 1
end

defmodule Shared do
  def speak_until(%Game{turn: turn} = game, max_turn) when turn <= max_turn,
    do: speak_until(speak(game), max_turn)

  def speak_until(%Game{} = game, _max_turn), do: game

  def speak(%Game{last: last, record: record, turn: turn}) do
    new_last =
      case Map.get(record, last) do
        nil -> :error
        {_} -> 0
        {i, j} -> i - j
      end

    new_record =
      case Map.get(record, new_last) do
        nil -> {turn}
        {i} -> {turn, i}
        {i, _} -> {turn, i}
      end

    %Game{
      last: new_last,
      record: Map.put(record, new_last, new_record),
      turn: turn + 1
    }
  end

  def init(starting_numbers), do: init(starting_numbers, %Game{})
  def init([], %Game{} = game), do: game

  def init([n | tail], %Game{record: record, turn: turn}) do
    init(tail, %Game{last: n, record: Map.put(record, n, {turn}), turn: turn + 1})
  end
end

part a

{starting_numbers, _} = Code.eval_string("[#{input}]")

starting_numbers
|> Shared.init()
|> Shared.speak_until(2020)
|> Map.get(:last)

part b

{starting_numbers, _} = Code.eval_string("[#{sample}]")

starting_numbers
|> Shared.init()
|> Shared.speak_until(30_000_000)
|> Map.get(:last)

# 8546398