— Day 2: Gift Shop —
Mix.install([{:kino_aoc, "~> 0.1"}])
Part 1
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2025", "2", System.fetch_env!("LB_AOC_SESSION_COOKIE"))
test_input = "11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124"
defmodule GiftShop do
def part_1(input) do
ranges = parse_ranges(input)
ranges
|> Enum.reduce([], fn range, acc ->
Enum.reduce(range, acc, fn id, acc ->
if id_invalid?(id) do
[id | acc]
else
acc
end
end)
end)
|> Enum.sum()
end
def part_2(input) do
ranges = parse_ranges(input)
max_chunk_size = max_chunk_size(ranges)
ranges
|> Enum.reduce([], fn range, acc ->
Enum.reduce(range, acc, fn id, acc ->
if id_invalid?(id, max_chunk_size) do
[id | acc]
else
acc
end
end)
end)
|> Enum.sum()
end
defp parse_ranges(input) do
input
|> String.split(",")
|> Enum.map(&create_range/1)
end
defp max_chunk_size(ranges) do
ranges
|> Enum.map(fn range ->
range.last |> Integer.digits() |> length() |> div(2)
end)
|> Enum.max()
end
defp create_range(range_string) do
{range_start, "-" <> range_end_string} = Integer.parse(range_string)
{range_end, _} = Integer.parse(range_end_string)
range_start..range_end
end
defp id_invalid?(id) when id <= 10, do: false
defp id_invalid?(id) do
digits = Integer.digits(id)
length = length(digits)
if rem(length, 2) != 0 do
false
else
{first, second} = Enum.split(digits, div(length, 2))
first == second
end
end
defp id_invalid?(id, _max_chunk_szie) when id <= 10, do: false
defp id_invalid?(id, max_chunk_size) do
[first | _rest] = digits = Integer.digits(id)
Enum.all?(digits, &(&1 == first)) || has_repeating_digits?(digits, max_chunk_size)
end
defp has_repeating_digits?(id_digits, max_chunk_size) do
Enum.reduce_while(2..max_chunk_size, false, fn
chunk_size, acc when length(id_digits) <= chunk_size ->
{:cont, acc}
chunk_size, acc ->
[first_chunk | _rest] = chunks = Enum.chunk_every(id_digits, chunk_size)
if Enum.all?(chunks, &(&1 == first_chunk)) do
{:halt, true}
else
{:cont, acc}
end
end)
end
end
# GiftShop.part_1(test_input)
GiftShop.part_1(puzzle_input)
Part 2
# GiftShop.part_2(test_input)
GiftShop.part_2(puzzle_input)