mirror of
https://github.com/rjNemo/ai_advent_code_2024
synced 2026-06-06 02:26:44 +00:00
109 lines
2.7 KiB
Elixir
109 lines
2.7 KiB
Elixir
defmodule AdventCode2024.Solutions.Day05 do
|
|
@moduledoc """
|
|
Day 5: Solution for Advent of Code 2024
|
|
"""
|
|
|
|
@behaviour AdventCode2024.Solution
|
|
|
|
@impl true
|
|
def solve(""), do: {:error, :no_input}
|
|
|
|
def solve(path \\ "priv/inputs/day05/input.txt") do
|
|
case File.read(path) do
|
|
{:ok, content} -> solve_content(content)
|
|
{:error, :enoent} -> {:error, :enoent}
|
|
_ -> {:error, :no_input}
|
|
end
|
|
end
|
|
|
|
def solve_content(""), do: {:error, :no_input}
|
|
|
|
def solve_content(content) do
|
|
{rules, updates} = parse_input(content)
|
|
valid_updates = Enum.filter(updates, &is_valid_update?(&1, rules))
|
|
sum = valid_updates |> Enum.map(&get_middle_number/1) |> Enum.sum()
|
|
{:ok, sum}
|
|
end
|
|
|
|
@impl true
|
|
def solve_part2(""), do: {:error, :no_input}
|
|
|
|
def solve_part2(path \\ "priv/inputs/day05/input.txt") do
|
|
case File.read(path) do
|
|
{:ok, content} -> solve_part2_content(content)
|
|
{:error, :enoent} -> {:error, :enoent}
|
|
_ -> {:error, :no_input}
|
|
end
|
|
end
|
|
|
|
def solve_part2_content(""), do: {:error, :no_input}
|
|
|
|
def solve_part2_content(content) do
|
|
{rules, updates} = parse_input(content)
|
|
invalid_updates = Enum.reject(updates, &is_valid_update?(&1, rules))
|
|
|
|
sum =
|
|
invalid_updates
|
|
|> Enum.map(&order_update(&1, rules))
|
|
|> Enum.map(&get_middle_number/1)
|
|
|> Enum.sum()
|
|
|
|
{:ok, sum}
|
|
end
|
|
|
|
defp parse_input(content) do
|
|
[rules_str, updates_str] = String.split(content, "\n\n", trim: true)
|
|
rules = parse_rules(rules_str)
|
|
updates = parse_updates(updates_str)
|
|
{rules, updates}
|
|
end
|
|
|
|
defp parse_rules(rules_str) do
|
|
rules_str
|
|
|> String.split("\n", trim: true)
|
|
|> Enum.map(fn rule ->
|
|
[first, second] = String.split(rule, "|")
|
|
{String.to_integer(first), String.to_integer(second)}
|
|
end)
|
|
end
|
|
|
|
defp parse_updates(updates_str) do
|
|
updates_str
|
|
|> String.split("\n", trim: true)
|
|
|> Enum.map(fn line ->
|
|
line
|
|
|> String.split(",")
|
|
|> Enum.map(&String.to_integer/1)
|
|
end)
|
|
end
|
|
|
|
defp is_valid_update?(update, rules) do
|
|
update
|
|
|> Enum.chunk_every(2, 1, :discard)
|
|
|> Enum.all?(fn [a, b] -> is_valid_order?(a, b, rules) end)
|
|
end
|
|
|
|
defp is_valid_order?(a, b, rules) do
|
|
not Enum.any?(rules, fn {x, y} -> x == b and y == a end)
|
|
end
|
|
|
|
defp get_middle_number(list) do
|
|
middle_index = div(length(list), 2)
|
|
Enum.at(list, middle_index)
|
|
end
|
|
|
|
defp order_update(update, rules) do
|
|
update
|
|
|> Enum.sort(fn a, b ->
|
|
case {should_come_before?(a, b, rules), should_come_before?(b, a, rules)} do
|
|
{true, false} -> true
|
|
{false, true} -> false
|
|
_ -> a > b
|
|
end
|
|
end)
|
|
end
|
|
|
|
defp should_come_before?(a, b, rules) do
|
|
Enum.any?(rules, fn {x, y} -> x == a and y == b end)
|
|
end
|
|
end
|