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/^(?[[:alpha:]]+)\{(?.*)\}$/, 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." -> &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