You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

56 lines
1.7 KiB
Elixir

defmodule Day5 do
def run do
{rules, updates} = parseFile("data.txt")
{validUpdates, invalidUpdates} = Enum.split_with(updates, &updateValid?(&1, rules))
validMiddles = Enum.map(validUpdates, &middleDigit/1)
IO.puts("Part 1: #{Enum.sum(validMiddles)}")
# sort the invalid ones with a custom sorter that looks for [a, b] in the rules list. if [a, b] exists, sort a before b
invalidSorted =
Enum.map(invalidUpdates, fn update ->
Enum.sort(update, fn first, second ->
Enum.member?(rules, [first, second])
end)
end)
invalidMiddles = Enum.map(invalidSorted, &middleDigit/1)
IO.puts("Part 2: #{Enum.sum(invalidMiddles)}")
end
defp parseFile(file) do
[topSection, bottomSection] = File.read!(file) |> String.split("\n\n")
rules = String.split(topSection, "\n") |> Enum.map(fn l -> String.split(l, "|") end)
updates =
String.split(bottomSection, "\n")
|> Enum.drop(-1)
|> Enum.map(fn l -> String.split(l, ",") end)
{rules, updates}
end
defp updateValid?(update, rules) do
Enum.reduce_while(rules, true, fn [left, right], acc ->
# if it doesn't contain both, or it does and they're in the right order
if !(Enum.member?(update, left) and Enum.member?(update, right)) or
Enum.find_index(update, &(&1 == left)) < Enum.find_index(update, &(&1 == right)) do
# continue and try the next one
{:cont, acc}
else
# otherwise halt the reduction, this update is invalid
{:halt, false}
end
end)
end
defp middleDigit(update) do
middle = trunc(length(update) / 2)
String.to_integer(Enum.at(update, middle))
end
end
Day5.run()