Advent of Code 2024 - Day 07
Mix.install([
{:req, "~> 0.5"},
{:benchee, "~> 1.3"}
])
Input
opts = [headers: [{"cookie", "session=#{System.fetch_env!("LB_AOC_SESSION")}"}]]
puzzle_input = Req.get!("https://adventofcode.com/2024/day/7/input", opts).body
puzzle_input =
String.split(puzzle_input, "\n", trim: true)
|> Enum.map(fn row ->
[sum, nums] = String.split(row, ":", trim: true)
sum = String.to_integer(sum)
nums = String.split(nums, " ", trim: true) |> Enum.map(&String.to_integer(&1))
{sum, nums}
end)
defmodule BridgeRepair do
def sum_of_sums(rows, operators) do
Task.async_stream(rows, fn {sum, nums} ->
[head | tail] = nums
if valid?(tail, sum, head, operators), do: sum, else: 0
end)
|> Enum.reduce(0, fn {:ok, x}, acc -> x + acc end)
end
def valid?(_nums, expected, acc, _operators) when acc > expected, do: false
def valid?(_nums, expected, acc, _operators) when expected == acc, do: true
def valid?([], _expected, _acc, _operators), do: false
def valid?([x | tail], expected, acc, operators) do
for operator <- operators do
case operator do
:multiply -> valid?(tail, expected, x * acc, operators)
:add -> valid?(tail, expected, x + acc, operators)
:concatenation -> valid?(tail, expected, concat_nums(acc, x), operators)
end
end
|> Enum.any?()
end
def concat_nums(a, b) when b < 10, do: a * 10 + b
def concat_nums(a, b) when b < 100, do: a * 100 + b
def concat_nums(a, b) when b < 1_000, do: a * 1000 + b
def concat_nums(a, b) do
a * Integer.pow(10, Integer.digits(b) |> length) + b
end
end
Puzzle 1
puzzle_1 = fn ->
operators = [:multiply, :add]
BridgeRepair.sum_of_sums(puzzle_input, operators)
end
puzzle_1.()
Puzzle 2
puzzle_2 = fn ->
operators = [:multiply, :add, :concatenation]
BridgeRepair.sum_of_sums(puzzle_input, operators)
end
puzzle_2.()
Benchmarks
Benchee.run(
%{
"puzzle_1" => fn -> puzzle_1.() end,
"puzzle_2" => fn -> puzzle_2.() end
})
Name |
ips |
average |
deviation |
median |
99th % |
puzzle_1 |
119.32 |
8.38 ms |
±5.76% |
8.32 ms |
9.90 ms |
puzzle_2 |
22.29 |
44.86 ms |
±5.46% |
44.67 ms |
62.88 ms |