Advent of code 2025 day 5
Mix.install([
{:kino, "~> 0.18"}
])
Part 1
https://adventofcode.com/2025/day/5
input = Kino.Input.textarea("Please give me input:")
[ranges_parts, ids_parts] =
Kino.Input.read(input)
|> String.split("\n\n", trim: true)
unique_ids =
String.split(ids_parts, "\n", trim: true) |> Enum.map(&String.to_integer(&1))
overlapping_ranges =
String.split(ranges_parts, "\n", trim: true)
|> Enum.map(fn range ->
[from, to] = String.split(range, "-")
String.to_integer(from)..String.to_integer(to)//1
end)
length(overlapping_ranges)
defmodule Part1 do
def remove_numbers(ids, range) do
Enum.reject(ids, fn ingredient_id -> ingredient_id in range end)
end
def get_spoiled_ingredients(overlapping_ranges, unique_ids) do
Enum.reduce_while(overlapping_ranges, unique_ids, fn range, ids_minus_fresh ->
new_ids_minus_fresh = remove_numbers(ids_minus_fresh, range)
if new_ids_minus_fresh == [] do
{:halt, []}
else
{:cont, new_ids_minus_fresh}
end
end)
end
end
spoiled_ids = Part1.get_spoiled_ingredients(overlapping_ranges, unique_ids)
length(unique_ids) - length(spoiled_ids)
Part 2
defmodule Part2 do
# ranges_without_overlap contains the handled ranges
def combine_ranges(from..to//1, low..high//1, ranges_without_overlap)
when low > to or high < from do
# no overlap
[low..high//1 | [from..to//1 | ranges_without_overlap]]
end
def combine_ranges(from..to//1, low..high//1, ranges_without_overlap) do
# There is a new combination to be made to eliminate the overlap.
[min(from, low)..max(to, high)//1 | ranges_without_overlap]
end
def loop_all_ranges_and_combine([]), do: []
def loop_all_ranges_and_combine([first_range | overlapping_ranges]) do
Enum.reduce(overlapping_ranges, [first_range], fn new_range,
[last_addition | ranges_without_overlap] ->
combine_ranges(last_addition, new_range, ranges_without_overlap)
end)
end
end
# by sorting the ranges first, there will be no need to start from the beginning of
# the list with ranges again when 2 ranges are combined.
sorted_overlapping_ranges = Enum.sort_by(overlapping_ranges, fn from..to//1 -> {from, to} end)
ranges_without_overlap = Part2.loop_all_ranges_and_combine(sorted_overlapping_ranges)
Enum.sum_by(ranges_without_overlap, fn from..to//1 -> to - from + 1 end)