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

Advent of code day 19

2024/livebooks/day-19.livemd

Advent of code day 19

Mix.install([
  {:kino, "~> 0.5.0"}
])

Setup input

example = Kino.Input.textarea("Please paste your input example:")
input = Kino.Input.textarea("Please paste your real input:")
[patterns, words] = example |> Kino.Input.read() |> String.split("\n\n")

patterns = patterns |> String.split(", ", trim: true) |> Enum.into(MapSet.new())
words = words |> String.split("\n", trim: true)
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
defmodule Solver do
  def possible?(word, patterns) do
    case word do
      "" ->
        1

      word ->
        Enum.reduce(patterns, 0, fn pattern, acc ->
          case String.starts_with?(word, pattern) do
            true ->
              acc +
                SimpleCache.get(Solver, :possible?, [
                  String.replace_prefix(word, pattern, ""),
                  patterns
                ])

            _ ->
              acc
          end
        end)
    end
  end
end
SimpleCache.init_cache()

Part 01

Enum.reduce(words, 0, fn word, acc ->
  case Solver.possible?(word, patterns) do
    0 -> acc
    _x -> acc + 1
  end
end)

Part 02

Enum.reduce(words, 0, fn word, acc ->
  case Solver.possible?(word, patterns) do
    0 -> acc
    x -> acc + x
  end
end)