Will Thomas' blog

AoC 2025 Day 2

2025-12-15, Monday


Day 2 of Advent of Code. Again, part 1 was fairly simple and straightforward. And again, part 2 gave me some minor issues I still don't quite understand. Let's get into it!

Part 1: A mischievous young elf has entered invalid product IDs into the gift shop register. A typical day at the North Pole. We are tasked with finding the invalid IDs, made obvious by being a pattern repeated twice (e.g. 123123), and sum them together to find the answer! Not too bad with some simple string manipulation.

First, we split the input by commas to get each range of IDs, then we split each range by '-' to get the start and end of the range:

const [begin, end] = range.trim().split('-')

then we can iterate over the IDs in the range

for (let test = parseInt(begin); test <= parseInt(end); ++test) {
	const t = test.toString()
	if (isInvalid(t)) sumOfInvalidIds += test
	if (isInvalid2(t)) sumPart2 += test // spoilers!
}

and finally just split the string in half and check both sides match or not:

const l = id.length / 2
// get first and second halves, compare
const partA = id.substring(0, l)
const partB = id.substring(l)
// if they match, this id is invalid
return partA == partB

Part 2: Actually, the half-repeated IDs is just half the problem! Really, the nonsense IDs could be a pattern repeated any number of times (e.g. 121212, 11111, etc), and now we have to sum all IDs made up of repetition.

I thought this was fairly straightforward after part 1, and my initial attempt barely differs from my final answer. I'm not sure exactly what was wrong, I just moved the calculation out to a separate function (after seeing this done by u/pipdibble again!) and maybe I changed something else or moving it around in this way made something clearer, but basically that gave me the correct answer. So I'll probably use this pattern again in future days!

My actual logic was based on what I originally had which differs a bit to pipdibble's (unlike yesterday where I basically just stole their idea!), but I took more inspiration from the structure of their code.

So the hard part here (of my simple-minded solution) is figuring out how many times to attempt to split the string, and how long each part is. Once we have that, we can iterate over the string to get all the substrings we need, and then finally compare that they all match. Simple, right?

Yeah, so simple that I had to write down examples on a paper notepad to get my head around it. I need a holiday - good thing Christmas is coming!

const isInvalid2 = (id) => {
	const l = id.length 

	// check every possible split of t
	for (let div = 2; div <= l; ++div) {
		// if length of t not divisible by div, then not a valid check
		if (l % div != 0) {
			continue
		}

		// split t into div parts of length l/div
		const partCount = div
		const partLength = l / div
		const parts = []
		for (let p = 0; p < partCount; ++p) {
			parts.push(
				id.substring(p * partLength, (p + 1) * partLength)
			)
		}

		// check all parts match or not
		let match = true
		for (let p = 1; p < partCount; ++p) {
			if (parts[0] != parts[p]) {  
				match = false
				break
			}
		}

		if (match) return true
	}

	return false
}

Phew! Well, it's finally over. Check the full code on GitHub.