Advent of Code - Day 5
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Problem
https://adventofcode.com/2024/day/5
I have yet to complete part 2. I feel it could be done with topological sort of rules, but wanted to find another solution.
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2024", "5", System.fetch_env!("LB_AOC_SESSION"))
defmodule Day5 do
def parse_rules(rules) do
rules
|> String.split(["\n", "|"], trim: true)
|> Enum.map(&String.to_integer/1)
|> Enum.chunk_every(2)
|> Enum.reduce(%{}, fn [a, b], map ->
map
|> Map.update(a, MapSet.new([b]), &MapSet.put(&1, b))
|> Map.put_new(b, MapSet.new())
end)
end
def parse(str) do
[rules, updates] = String.split(str, "\n\n")
updates = String.split(updates, "\n")
|> Enum.map(fn x -> String.split(x, ",") |> Enum.map(&String.to_integer/1) end)
rules = parse_rules(rules)
{rules, updates}
end
def correct_order?([], _), do: true
def correct_order?([page | pages], rules) do
rule = Map.fetch!(rules, page)
Enum.all?(pages, &Enum.member?(rule, &1)) and correct_order?(pages, rules)
end
def add_middle_pages(updates) do
Enum.reduce(updates, 0, fn x, acc ->
acc + Enum.at(x, div(length(x),2))
end)
end
def solve_part1(str) do
{rules, updates } = parse(str)
Enum.filter(updates, fn pages ->
correct_order?(pages, rules)
end)
|> add_middle_pages()
end
def sort(list, rules) do
Enum.reduce_while(list, list, fn _, current_list ->
sorted = do_sort(current_list, [], rules)
if sorted == current_list do
{:halt, sorted}
else
{:cont, sorted}
end
end)
end
def do_sort([], acc, _), do: acc
def do_sort([head], acc, _), do: acc ++ [head]
def do_sort([first, second | tail], acc, rules) do
if correct_order?([first, second], rules) do
do_sort([second | tail], acc ++ [first], rules)
else
do_sort([first | tail], acc ++ [second], rules)
end
end
def solve_part2(str) do
{ rules, updates } = parse(str)
updates
|> Enum.reject(&correct_order?(&1, rules))
|> Enum.map(&sort(&1, rules))
|> add_middle_pages()
end
end
example_input = "47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13
75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47"
Day5.solve_part1(puzzle_input)
Day5.solve_part2(puzzle_input)