diff options
-rw-r--r-- | src/day05.exs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/day05.exs b/src/day05.exs new file mode 100644 index 0000000..e950b06 --- /dev/null +++ b/src/day05.exs @@ -0,0 +1,80 @@ +defmodule Day05 do + def parse_integer_list(list, split) do + list + |> String.split(split, trim: true) + |> Enum.map(&String.to_integer/1) + end + + def parse_data(data) do + [rules, jobs] = data + |> String.split("\n\n", trim: true) + + rules = rules + |> String.split("\n", trim: true) + |> Enum.map(&parse_integer_list(&1, "|")) + |> Enum.group_by(&hd/1, &hd(tl(&1))) + |> Enum.into(%{}, fn {k, v} -> {k, MapSet.new(v)} end) + + jobs = jobs + |> String.split("\n", trim: true) + |> Enum.map(&parse_integer_list(&1, ",")) + + {rules, jobs} + end + + def part1({rules, jobs}) do + jobs + |> Enum.filter(&job_okay?(&1, rules)) + |> Enum.map(&middle_page/1) + |> Enum.sum() + end + + def job_okay?(job, rules) do + case job do + [] -> + true + [page | rest] -> + page_okay?(page, rest, rules) and + job_okay?(rest, rules) + end + end + + def page_okay?(page, rest, rules) do + rest + |> Enum.all?(&Map.get(rules, &1, %MapSet{}) |> MapSet.member?(page) == false) + end + + def middle_page(job) do + job |> Enum.at(job |> length() |> div(2)) + end + + def part2({rules, jobs}) do + jobs + |> Enum.reject(&job_okay?(&1, rules)) + |> Enum.map(&fix_job(&1, rules)) + |> Enum.map(&middle_page/1) + |> Enum.sum() + end + + def fix_job(job, rules, acc \\ []) do + case job do + [] -> + Enum.reverse(acc) + job -> + {l, r} = Enum.split_with(job, &page_okay?(&1, job, rules) == false) + [next, rest] = [hd(r), l ++ tl(r)] + fix_job(rest, rules, [next | acc]) + end + end +end + +data = IO.read(:stdio, :eof) |> Day05.parse_data() + +{time1 , ans1} = :timer.tc(fn -> Day05.part1(data) end) +IO.puts("Time : #{time1 / 1000000}") +IO.puts("Answer: #{ans1}") + +{time2 , ans2} = :timer.tc(fn -> Day05.part2(data) end) +IO.puts("Time : #{time2 / 1000000}") +IO.puts("Answer: #{ans2}") + |