Advent of code day 11
Mix.install([
{:kino, "~> 0.5.0"}
])
Setup input
example = Kino.Input.textarea("Please paste your input example:")
stones =
example
|> Kino.Input.read()
|> String.split(" ", trim: true)
|> Enum.map(&String.to_integer/1)
# copied from elixir docs
defmodule SimpleCache do
@moduledoc """
A simple ETS based cache for expensive function calls.
"""
def init_cache() do
if :ets.whereis(:simple_cache) != :undefined do
:ets.delete(:simple_cache)
end
:ets.new(:simple_cache, [:set, :public, :named_table])
end
@doc """
Retrieve a cached value or apply the given function caching and returning
the result.
"""
def get(mod, fun, args, opts \\ []) do
case lookup(mod, fun, args) do
nil ->
ttl = Keyword.get(opts, :ttl, 3600)
cache_apply(mod, fun, args, ttl)
result ->
result
end
end
defp lookup(mod, fun, args) do
case :ets.lookup(:simple_cache, [mod, fun, args]) do
[result | _] -> check_freshness(result)
[] -> nil
end
end
defp check_freshness({_mfa, result, expiration}) do
cond do
expiration > :os.system_time(:seconds) -> result
:else -> nil
end
end
defp cache_apply(mod, fun, args, ttl) do
result = apply(mod, fun, args)
expiration = :os.system_time(:seconds) + ttl
:ets.insert(:simple_cache, {[mod, fun, args], result, expiration})
result
end
end
SimpleCache.init_cache()
# changed my mind. lets use memo xD
defmodule Blinker do
def blink(_stone, 0), do: 1
def blink(0, steps), do: SimpleCache.get(Blinker, :blink, [1, steps - 1])
def blink(stone, steps) do
digits = Integer.digits(stone)
case rem(Enum.count(digits), 2) do
0 ->
{a, b} = Enum.split(digits, div(Enum.count(digits), 2))
SimpleCache.get(Blinker, :blink, [Integer.undigits(a), steps - 1]) +
SimpleCache.get(Blinker, :blink, [Integer.undigits(b), steps - 1])
1 ->
SimpleCache.get(Blinker, :blink, [stone * 2024, steps - 1])
end
end
end
Part 01
Enum.reduce(stones, 0, fn stone, acc ->
Blinker.blink(stone, 25) + acc
end)
Part 02
Enum.reduce(stones, 0, fn stone, acc ->
Blinker.blink(stone, 75) + acc
end)