AoC 2024/05
Mix.install([
{:kino, "~> 0.14.2"}
])
Section
input = Kino.Input.textarea("input")
defmodule Day5 do
def parse_input(input) do
[rules_str, updates_str] = String.split(input, "\n\n")
rules =
rules_str
|> String.split("\n")
|> Enum.map(fn rule_str ->
[from_str, to_str] = String.split(rule_str, "|")
{String.to_integer(from_str), String.to_integer(to_str)}
end)
|> Enum.group_by(fn {from, _to} -> from end, fn {_from, to} -> to end)
updates =
updates_str
|> String.split("\n")
|> Enum.map(fn pages_str ->
String.split(pages_str, ",")
|> Enum.map(&String.to_integer/1)
end)
{rules, updates}
end
def solve1(input) do
parse_input(input)
|> check_rules_updates()
|> Enum.filter(fn {result, _} -> result end)
|> Enum.map(fn {_, update} -> middle_page_number(update) end)
|> Enum.sum()
end
def check_rules_updates({rules, updates}) do
Enum.map(updates, fn update ->
Enum.reduce_while(update, {MapSet.new(), update}, fn page, {processed_pages, update} ->
case Map.fetch(rules, page) do
{:ok, to_be_printed_after_pages} ->
if MapSet.intersection(processed_pages, MapSet.new(to_be_printed_after_pages)) == MapSet.new() do
{:cont, {MapSet.put(processed_pages, page), update}}
else
{:halt, {false, update}}
end
_ -> {:cont, {MapSet.put(processed_pages, page), update}}
end
end)
end)
end
def middle_page_number(update) do
middle_index = div(Enum.count(update), 2)
Enum.at(update, middle_index)
end
def solve2(input) do
input
|> parse_input()
|> then(fn {rules, updates} ->
check_rules_updates({rules, updates})
|> Stream.reject(fn {result, _} -> result end)
|> Stream.map(fn {_result, update} -> update end)
|> then(fn updates ->
find_correctly_ordered_updates({rules, updates})
|> Stream.map(fn updates ->
Stream.filter(updates, fn {result, _} -> result end)
|> Stream.map(fn {_, update} -> middle_page_number(update) end)
|> Enum.sum()
end)
|> Enum.sum()
end)
end)
end
def find_correctly_ordered_updates({rules, updates}) do
Enum.map(updates, fn update ->
check_rules_updates({rules, permutations(update)})
end)
end
def permutations([]), do: [[]]
def permutations(list) do
for elem <- list, rest <- permutations(list--[elem]), do:
([elem|rest])
end
end
{:module, Day5, <<70, 79, 82, 49, 0, 0, 27, ...>>, {:permutations, 1}}
solve1
Kino.Input.read(input)
|> Day5.solve1()
143
input
|> Kino.Input.read()
|> Day5.parse_input()
{%{
29 => ~c"\r",
47 => [53, 13, 61, 29],
53 => [29, 13],
61 => [13, 53, 29],
75 => [29, 53, 47, 61, 13],
97 => [13, 61, 47, 29, 53, 75]
},
[
[75, 47, 61, 53, 29],
[97, 61, 53, 29, 13],
[75, 29, 13],
~c"Ka/=5",
[61, 13, 29],
[97, 13, 75, 29, 47]
]}
solve2
Kino.Input.read(input)
|> Day5.solve2()
123
IO.inspect ~c"aK/=5", charlists: :as_lists
[97, 75, 47, 61, 53]
~c"aK/=5"
rules = [
{47, 13},
{75, 47},
{97, 75},
{47, 61},
{75, 61},
{47, 29},
{75, 13},
{53, 13}
]
|> Enum.group_by(fn {from, _to} -> from end, fn {_from, to} -> to end)
%{47 => [13, 61, 29], 53 => ~c"\r", 75 => ~c"/=\r", 97 => ~c"K"}
rules = %{75 => [29, 53, 47, 61, 13]}
%{75 => [29, 53, 47, 61, 13]}
updates = [[97, 13, 75, 29, 47]]
[[97, 13, 75, 29, 47]]
Day5.check_rules_updates({rules, updates})
[false: [97, 13, 75, 29, 47]]
rules = %{
29 => ~c"\r",
47 => [53, 13, 61, 29],
53 => [29, 13],
61 => [13, 53, 29],
75 => [29, 53, 47, 61, 13],
97 => [13, 61, 47, 29, 53, 75]
}
%{
29 => ~c"\r",
47 => [53, 13, 61, 29],
53 => [29, 13],
61 => [13, 53, 29],
75 => [29, 53, 47, 61, 13],
97 => [13, 61, 47, 29, 53, 75]
}
Day5.check_rules_updates({rules, [[97,13,75,29,47]]})
[false: [97, 13, 75, 29, 47]]
defmodule Test do
def permutations([]), do: [[]]
def permutations(list) do
for elem <- list, rest <- permutations(list--[elem]), do:
([elem|rest])
end
end
{:module, Test, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:permutations, 1}}
Test.permutations([13, 53, 29])
[[13, 53, 29], [13, 29, 53], [53, 13, 29], [53, 29, 13], [29, 13, 53], [29, 53, 13]]