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

Advent 2024 - Day 5

day5.livemd

Advent 2024 - Day 5

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

Setup

input = Kino.Input.textarea("Please paste your input file")
[rules, updates] = input |> Kino.Input.read() |> String.split("\n\n")

rules = rules
  |> String.split("\n")
  |> Enum.map(fn rule ->
    rule
    |> String.split("|")
    |> Enum.map(&(String.to_integer(&1)))
  end)

updates = updates
  |> String.split("\n")
  |> Enum.map(fn update ->
    update
    |> String.split(",")
    |> Enum.map(&(String.to_integer(&1)))
  end)
rule_lookup = rules
  |> Enum.group_by(fn [a, _b] -> a end)
  |> Enum.map(fn {k, v} ->
    {k, v |> Enum.map(fn [_a, b] -> b end) |> MapSet.new()}
  end)
  |> Map.new()
check_valid = fn update ->
  for {num, index} <- Enum.with_index(update) do
    {before_updates, _after_updates} = update |> Enum.split(index)
    for before_update <- before_updates do
      Enum.member?(Map.get(rule_lookup, before_update, []), num)
    end
  end
  |> List.flatten()
  |> Enum.all?()
end

Part 1

for update <- updates do
  is_valid = check_valid.(update)
  
  if is_valid do
    Enum.at(update, floor(length(update) / 2))
  else
    nil
  end
end
|> Enum.filter(&amp;(&amp;1))
|> Enum.sum()

Part 2

for update <- updates do
  is_valid = check_valid.(update)

  if is_valid do
    nil
  else
    update
    |> Enum.sort(fn a, b ->
      Enum.member?(Map.get(rule_lookup, a, []), b)
    end)
    |> Enum.at(floor(length(update) / 2))
  end
end
|> Enum.filter(&amp;(&amp;1))
|> Enum.sum()