Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

AoC 2024/05

aoc-2024-05.livemd

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]]