KeithFrost
Advent of Code 2025 - Day 3
2025 Dec 03
Lobby
defmodule Joltage do
def parse_line(s) do
String.trim(s)
|> to_charlist()
|> Enum.map(fn ch ->
if ch <= ?9 and ch >= ?0 do
ch - ?0
end
end)
end
def parse(lines) do
Enum.map(lines, &parse_line/1)
end
def max_prefix(bank) do
[_last | rbank] = Enum.reverse(bank)
Enum.max(rbank)
end
def max_joltage(bank) do
max1 = max_prefix(bank)
[_max1 | tail] = Enum.drop_while(bank, fn j -> j < max1 end)
max1 * 10 + Enum.max(tail)
end
def sum_max_joltages(banks) do
Enum.reduce(banks, 0, fn bank, sum ->
sum + max_joltage(bank)
end)
end
end
test_banks = """
987654321111111
811111111111119
234234234234278
818181911112111
""" |> String.split("\n", trim: true)
|> Joltage.parse()
|> IO.inspect()
Enum.map(test_banks, &Joltage.max_joltage/1)
|> IO.inspect(charlists: :as_lists)
Joltage.sum_max_joltages(test_banks)
input_banks = File.stream!(__DIR__ <> "/dec-03-input.txt")
|> Joltage.parse()
Joltage.sum_max_joltages(input_banks)
Part Two
defmodule Joltage2 do
def max_prefix(bank, n) do
Enum.reverse(bank)
|> Enum.drop(n - 1)
|> Enum.max()
end
@batteries 12
def max_joltage(bank, n \\ @batteries, acc \\ 0) do
if n < 1 do
acc
else
max1 = max_prefix(bank, n)
[_max1 | tail] = Enum.drop_while(bank, fn j -> j < max1 end)
max_joltage(tail, n - 1, acc * 10 + max1)
end
end
def sum_max_joltages(banks) do
Enum.reduce(banks, 0, fn bank, sum ->
sum + max_joltage(bank)
end)
end
end
Enum.map(test_banks, &Joltage2.max_joltage/1)
|> IO.inspect(charlists: :as_lists)
Joltage2.sum_max_joltages(test_banks)
Joltage2.sum_max_joltages(input_banks)
Most Liked
hauleth
Parse
batteries =
puzzle_input
|> String.split("\n", trim: true)
|> Enum.map(fn row ->
row
|> String.to_charlist()
|> Enum.map(& &1 - ?0)
end)
Implementation
defmodule Joltage do
def make_largest(list, n) do
to_remove = length(list) - n
Enum.reduce(1..to_remove, list, fn _, acc -> make_larger(acc) end)
end
def make_larger([_]), do: []
def make_larger([a, b | rest]) when a < b, do: [b | rest]
def make_larger([b | rest]), do: [b | make_larger(rest)]
end
Part 1
Enum.sum_by(batteries, &Integer.undigits(Joltage.make_largest(&1, 2)))
Part 2
Enum.sum_by(batteries, &Integer.undigits(Joltage.make_largest(&1, 12)))
All thanks to simple observation that to make number larger you need to drop first digit that is smaller than the next one or last digit. Now apply it N times to be left with just required amount of digits and you are good to go.
vkryukov
The algorithm is pretty straightforward: to take k largest batteries from a list of n, take the earliest largest digit among the first (n - k + 1), then iterate for all the digits after that one.
defmodule Y2025.Day03 do
def digits(s) do
s
|> String.graphemes()
|> Enum.map(&String.to_integer(&1))
end
def first_digit(digits, k) do
n = length(digits)
digits
|> Enum.take(n - k + 1)
|> Enum.with_index()
|> Enum.max_by(fn {a, i} -> {a, -i} end)
end
def max_digits(digits, k) do
k..1//-1
|> Enum.reduce({digits, 0}, fn k, {digits, acc} ->
{d, pos} = first_digit(digits, k)
{digits |> Enum.drop(pos + 1), acc * 10 + d}
end)
|> elem(1)
end
def max_joltage(s, k \\ 2) do
digits(s)
|> max_digits(k)
end
def part1(s, k \\ 2) do
s
|> String.split("\n")
|> Enum.map(&max_joltage(&1, k))
|> Enum.sum()
end
def part2(s) do
part1(s, 12)
end
end
BartOtten
Here we go.
Who knows?
How to do a ‘selective capture’?
The reducer passes 2 arguments to the anonymous function. Thought I could simply do (&2) but that is not allowed. &1 has to be used. The dirty trick is to (&2 || &1) when you are certain &2 will never be falsy but it is stretching the limits.
Could have gone with a simple fn but am wondering if someone knows a nice solid trick.
defmodule Aoc2025.Solutions.Y25.Day03 do
alias AoC.Input
def parse(input, _part) do
Input.read!(input)
|> String.trim()
|> String.split("\n")
|> Enum.map(&String.to_charlist/1)
end
def part_one(problem) do
solve(problem, 2)
end
def part_two(problem) do
solve(problem, 12)
end
def solve(problem, limit) do
problem
|> Stream.map(&keep_highest(&1, limit))
|> Stream.map(&to_string/1)
|> Stream.map(&String.to_integer/1)
|> Enum.sum()
end
def keep_highest(bank, limit) do
discard = length(bank) - limit
Enum.reduce(1..discard, bank, &maximize/2)
end
def maximize(_reduction, bank), do: maximize(bank)
def maximize([x, s]), do: [max(x, s)]
def maximize([l, r | rest]) when l < r, do: [r | rest]
def maximize([l, r | rest]), do: [l | maximize([r | rest])]
end
Edit 1: You can play “spot the differences” with @hauleth solution ![]()
Popular in Challenges
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








