diff --git a/2024/README.md b/2024/README.md index 3bc4c6b..b372483 100644 --- a/2024/README.md +++ b/2024/README.md @@ -2,7 +2,7 @@ | S | M | T | W | T | F | S | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | -| [1] | [2] | [3] | [4] | [5] | [6] | 7 | +| [1] | [2] | [3] | [4] | [5] | [6] | [7] | | 8 | 9 | 10 | 11 | 12 | 13 | 14 | | 15 | 16 | 17 | 18 | 19 | 20 | 21 | | 22 | 23 | 24 | 25 | | | | @@ -13,3 +13,4 @@ [4]: ./lib/2024/4.ex [5]: ./lib/2024/5.ex [6]: ./lib/2024/6.ex +[7]: ./lib/2024/7.ex diff --git a/2024/lib/2024/7.ex b/2024/lib/2024/7.ex new file mode 100644 index 0000000..88d1e8e --- /dev/null +++ b/2024/lib/2024/7.ex @@ -0,0 +1,45 @@ +import AOC +import AOC.Prelude + +aoc 2024, 7 do + def p1(input) do + ops = [&Kernel.+/2, &Kernel.*/2] + calibration_result(input, ops) + end + + def p2(input) do + ops = [&Kernel.+/2, &Kernel.*/2, &String.to_integer("#{&1}#{&2}")] + calibration_result(input, ops) + end + + defp calibration_result(input, ops) do + input + |> read_equations() + |> Enum.filter(&solvable?(&1, ops)) + |> Enum.map(&elem(&1, 0)) + |> Enum.sum() + end + + defp solvable?({answer, [acc | nums]}, ops), do: solvable?(nums, ops, answer, acc) + + defp solvable?([], _ops, answer, answer), do: true + defp solvable?([], _ops, _answer, _acc), do: false + defp solvable?(_nums, _ops, answer, acc) when acc > answer, do: false + + defp solvable?([n | rest], ops, answer, acc) do + Enum.any?(ops, &solvable?(rest, ops, answer, &1.(acc, n))) + end + + ## input + + defp read_equations(input) do + input + |> lines() + |> Enum.map(&String.split(&1, ": ")) + |> Enum.map(fn groups -> + [&String.to_integer/1, &ints/1] + |> Enum.zip_with(groups, &apply(&1, [&2])) + |> List.to_tuple() + end) + end +end diff --git a/2024/lib/aoc/prelude.ex b/2024/lib/aoc/prelude.ex new file mode 100644 index 0000000..6b356b1 --- /dev/null +++ b/2024/lib/aoc/prelude.ex @@ -0,0 +1,30 @@ +defmodule AOC.Prelude do + @moduledoc """ + Commonly used functions + """ + + @doc """ + Splits a String input into lists of lines. + + Excludes any leading or trailing lines from the output list. + """ + @spec lines(String.t()) :: [String.t()] + def lines(str) do + String.split(str, "\n", trim: true) + end + + @doc """ + Takes a string containing multiple integers and returns a list of the parsed + integers. + + The input is split on the given seperator. A single space is used if none is + provided. + """ + @spec ints(String.t()) :: [integer()] + @spec ints(String.t(), separator :: String.t()) :: [integer()] + def ints(str, separator \\ " ") do + str + |> String.split(separator, trim: true) + |> Enum.map(&String.to_integer/1) + end +end diff --git a/README.md b/README.md index 25b00d7..90441e8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ | [2021] | **43/50** 🌟 | Elixir | | [2022] | **14/50** 🌟 | Elixir, Haskell | | [2023] | **19/50** 🌟 | Elixir, Haskell | -| [2024] | **12/50** 🌟 | Elixir | +| [2024] | **14/50** 🌟 | Elixir | | **Total** | **162** 🌟| | [2015]: ./2015