From 9808ad404cbb1fa8806a2815d2fb5e9b1415007b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Mon, 9 Dec 2024 10:19:50 +1300 Subject: [PATCH] Solve day 5 --- lib/aoc2024/day_05.ex | 44 ++++++++++++++++++++++++++++++++++++++----- lib/aoc2024/utils.ex | 22 +++++++++++++--------- test/aoc2024_test.exs | 37 ++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 14 deletions(-) diff --git a/lib/aoc2024/day_05.ex b/lib/aoc2024/day_05.ex index a48647e..b3effb6 100644 --- a/lib/aoc2024/day_05.ex +++ b/lib/aoc2024/day_05.ex @@ -1,13 +1,47 @@ defmodule Aoc2024.Day05 do def parse(input) do - input |> String.split("\n", trim: true) + [rules_raw, updates_raw] = input |> String.trim() |> String.split("\n\n") + rules = Aoc2024.Utils.parse_rows_of_integers(rules_raw, "|") + updates = Aoc2024.Utils.parse_rows_of_integers(updates_raw, ",") + {rules, updates} end - def part1(_lines) do - :todo1 + defp sort([], _rules), do: %{was_sorted?: true, list: []} + + defp sort([head | tail], rules) do + result = + tail + |> Enum.reduce(%{sorted?: true, revlist: [], previous: head}, fn elem, acc -> + if rules |> Enum.member?([elem, acc.previous]) do + %{sorted?: false, revlist: [elem | acc.revlist], previous: acc.previous} + else + %{sorted?: acc.sorted?, revlist: [acc.previous | acc.revlist], previous: elem} + end + end) + + partially_sorted = [result.previous | result.revlist] |> Enum.reverse() + + if result.sorted? do + %{was_sorted?: true, list: partially_sorted} + else + %{was_sorted?: false, list: sort(partially_sorted, rules).list} + end end - def part2(_lines) do - :todo2 + def part1({rules, updates}) do + updates + |> Enum.filter(fn update -> sort(update, rules).was_sorted? end) + |> Enum.map(fn update -> update |> Enum.at(length(update) |> div(2)) end) + |> Enum.sum() + end + + def part2({rules, updates}) do + updates + |> Enum.map(fn update -> sort(update, rules) end) + |> Enum.filter(fn sort_result -> not sort_result.was_sorted? end) + |> Enum.map(fn sort_result -> + sort_result.list |> Enum.at(length(sort_result.list) |> div(2)) + end) + |> Enum.sum() end end diff --git a/lib/aoc2024/utils.ex b/lib/aoc2024/utils.ex index e1b9e27..588d23c 100644 --- a/lib/aoc2024/utils.ex +++ b/lib/aoc2024/utils.ex @@ -1,16 +1,20 @@ defmodule Aoc2024.Utils do - def parse_rows_of_integers(input) do + def parse_integers(input, separator \\ ~r/\s+/) do + input + |> String.split(separator) + |> Enum.map(fn int_str -> + case int_str |> Integer.parse() do + {int, ""} -> int + _ -> raise "Invalid integer #{int_str}" + end + end) + end + + def parse_rows_of_integers(input, separator \\ ~r/\s+/) do input |> String.split("\n", trim: true) |> Enum.map(fn line -> - line - |> String.split(~r/\s+/) - |> Enum.map(fn int_str -> - case int_str |> Integer.parse() do - {int, ""} -> int - _ -> raise "Invalid integer #{int_str}" - end - end) + parse_integers(line, separator) end) end end diff --git a/test/aoc2024_test.exs b/test/aoc2024_test.exs index 3d3976b..fb3873b 100644 --- a/test/aoc2024_test.exs +++ b/test/aoc2024_test.exs @@ -70,4 +70,41 @@ defmodule Aoc2024Test do assert Aoc2024.Day04.part1(parsed_input) == 18 assert Aoc2024.Day04.part2(parsed_input) == 9 end + + test "Day 5" do + 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 + """ + + parsed_input = Aoc2024.Day05.parse(input) + assert Aoc2024.Day05.part1(parsed_input) == 143 + assert Aoc2024.Day05.part2(parsed_input) == 123 + end end