aoc/23/elixir/lib/days/day19.ex
2023-12-19 20:08:45 +01:00

103 lines
2.6 KiB
Elixir

defmodule AOC.Day19 do
# use AOC.Day, day: 19, input: "example"
use AOC.Day, day: 19
def string_to_action("R"), do: :reject
def string_to_action("A"), do: :accept
def string_to_action(workflow), do: {:workflow, workflow}
def parse_input(lines) do
[workflows, _, ratings] = Enum.chunk_by(lines, &(&1 == ""))
workflows =
Enum.map(workflows, fn line ->
%{"name" => name, "rules" => rules} =
Regex.named_captures(~r/^(?<name>[[:alpha:]]+)\{(?<rules>.*)\}$/, line)
rules =
rules
|> String.split(",")
|> Enum.map(fn rule ->
if String.contains?(rule, ":") do
{property, rest} = String.split_at(rule, 1)
{operation, rest} = String.split_at(rest, 1)
[count, action] = String.split(rest, ":")
action = string_to_action(action)
count = String.to_integer(count)
operation =
case operation do
"<" -> &Kernel.</2
">" -> &Kernel.>/2
end
fn part ->
value = Map.fetch!(part, property)
if operation.(value, count) do
action
else
:continue
end
end
else
action = string_to_action(rule)
fn _ -> action end
end
end)
{name, rules}
end)
|> Enum.into(%{})
ratings =
Enum.map(ratings, fn line ->
line
|> String.trim_leading("{")
|> String.trim_trailing("}")
|> String.split(",")
|> Enum.map(fn property ->
[name, value] = String.split(property, "=")
{name, String.to_integer(value)}
end)
|> Enum.into(%{})
end)
{workflows, ratings}
end
def perform_workflow([rule | tl], rating) do
case rule.(rating) do
:continue -> perform_workflow(tl, rating)
action -> action
end
end
def sort_rating(workflows, rating, current_workflow_name) do
workflow = Map.fetch!(workflows, current_workflow_name)
case perform_workflow(workflow, rating) do
{:workflow, next_workflow_name} ->
sort_rating(workflows, rating, next_workflow_name)
action ->
action
end
end
def part1({workflows, ratings}) do
Enum.filter(ratings, fn rating ->
sort_rating(workflows, rating, "in") == :accept
end)
|> Enum.map(fn x ->
Enum.map(x, &elem(&1, 1))
|> Enum.sum()
end)
|> Enum.sum()
end
def part2(_input) do
"TOD"
end
end