— 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"))
{:ok,
"5959566378-5959623425,946263-1041590,7777713106-7777870316,35289387-35394603,400-605,9398763-9592164,74280544-74442206,85684682-85865536,90493-179243,202820-342465,872920-935940,76905692-76973065,822774704-822842541,642605-677786,3759067960-3759239836,1284-3164,755464-833196,52-128,3-14,30481-55388,844722790-844967944,83826709-83860070,9595933151-9595993435,4216-9667,529939-579900,1077949-1151438,394508-486310,794-1154,10159-17642,5471119-5683923,16-36,17797-29079,187-382"}
test_input = "11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124"
"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
{:module, GiftShop, <<70, 79, 82, 49, 0, 0, 23, ...>>, {:has_repeating_digits?, 2}}
# GiftShop.part_1(test_input)
GiftShop.part_1(puzzle_input)
19605500130
Part 2
# GiftShop.part_2(test_input)
GiftShop.part_2(puzzle_input)
36862281418