
AoC 2025, Day 2 - Gift Shop
Wednesday, December 3, 2025 at 3:02 AM
Another day, another puzzle. This time, we have Day 2: Gift Shop. Let's get to it. Again, spoilers are below for this puzzle. Don't read it if you want to solve this yourself.
As you traverse through the labyrinth of Santa's workshop, you walk through a gift shop, where a store clerk immediately needs your help. One of the younger elves screwed up the product database by adding tons of invalid IDs. You are tasked with finding them.
The puzzle input is a list of ID ranges, separated by commas:
11-22,95-115,998-1012,1188511880-1188511890,222220-222224,
1698522-1698528,446443-446449,38593856-38593862,565653-565659,
824824821-824824827,2121212118-2121212124
The elf who screwed things up didn't use a complex pattern. You have to search for numbers where it only contains a sequence of digits that are repeated. As an example, 123123 is an invalid ID, but 1234123 is valid because the entire ID isn't just a repeated set of digits.
Part 1 is to find and add up all the invalid IDs where the whole ID is a pattern that repeats twice.
Part 2 is like Part 1, except the pattern repeats twice or more.
Our puzzle input will be a JSON array:
["11-22", "95-115", "998-1012"]
Reading the input, we need to split the array element into two Number variables:
let [first, last] = i.split("-").map(Number);
Then we use a for loop, using our first and last numbers as its range:
for (var j = first; j <= last; j++) {
Within the loop, we will be doing string comparisons, so we also need a String variable that contains the current iteration number:
let jStr = j.toString();
Now we're ready to analyze some data.
Because we are looking for IDs where the entire number is a pattern that only repeats twice, we can make the general assumption that all IDs with an odd length can be ignored. This pattern can only be found in IDs with an even length.
We can also assume that we only have to search for one pattern state, in which the first half of the ID matches the second half. IDs of 123123, 54325432, and 10031003, for example, are considered invalid due to our matching pattern.
With these assumptions, we can solve Part 1 in just a few lines of code:
if (jStr.length % 2 == 0) {
let half = jStr.length / 2;
if (
jStr.substring(0, half) == jStr.substring(j.toString().length - half)
) {
sum += j;
}
}
This part relies on our trusty friend, the Regular Expression. I'm sure there's a more efficient process for this, but I eventually went with another for loop that uses 0 and the current number iteration's length as its range:
for (var k = 1; k <= jStr.length; k++) {
From there, I use the k value to grab ever larger patterns in my iteration number, stuffing that string into a RegExp object, then matching that expression against the iteration:
let pattern = new RegExp(jStr.substring(0, k), "g");
let matches = jStr.matchAll(pattern).toArray();
Finally, we check our matches. If we have at least two matches AND all those matches join together to match the length of our original iteration, we have an invalid ID:
if (
matches.length >= 2 &&
jStr.substring(0, k).length * matches.length == jStr.length
) {
sum2 += j;
break;
}
Boom, puzzle done.
Now that all of it works, we can improve the code to look cleaner and work more efficiently.
We can change the Part 1 solution to use ternary operation instead of if statements:
let jStr = j.toString(),
jHalf = jStr.length / 2;
sum +=
jStr.length % 2 == 0 &&
jStr.substring(0, jHalf) == jStr.substring(j.toString().length - jHalf)
? j
: 0;
We can improve processing time by limiting Part 2's matching logic to only go to the halfway point of an ID, since all matching beyond halfway will always result in failure:
for (var k = 1; k <= jHalf; k++) {
Easier than yesterday, mostly. Still, a fun one. I swear, these elves probably write their goddamn passwords on sticky notes or something.
My final code:
var data2 = require("./day02.json");
const Day2A = (d) => {
let sum = 0,
sum2 = 0;
d.forEach((i) => {
let [first, last] = i.split("-").map(Number);
for (var j = first; j <= last; j++) {
let jStr = j.toString(),
jHalf = jStr.length / 2;
sum +=
jStr.length % 2 == 0 &&
jStr.substring(0, jHalf) == jStr.substring(j.toString().length - jHalf)
? j
: 0;
for (var k = 1; k <= jHalf; k++) {
let pattern = new RegExp(jStr.substring(0, k), "g");
let matches = jStr.matchAll(pattern).toArray();
if (
matches.length >= 2 &&
jStr.substring(0, k).length * matches.length == jStr.length
) {
sum2 += j;
break;
}
}
}
});
return `${sum} - ${sum2}`;
};
console.log(Day2A(data2));