103 lines
2.6 KiB
Elixir
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
|