Let's solve the last day of Advent of Code 2025 and collect all 50 stars!

AOC 2024, Day 25: Locks, Keys and Stars!


We made it to the last day of Advent of Code, Day 25! Let’s figure out how to solve the last puzzle of the year!


The below is a guest post by the amazing Shraddha Agrawal.


Part 1

Input is a series of 2D grid. Each grid either represents a lock or a key. A grid represents a lock if the top row is filled with # . A grid is a key is the top row is filled with ..

Consider the following lock and key pair:

Part 1 and ans

They do not fit together as in the last column, the key overlaps the lock.

Rules for a pair of lock and key to fit together:

  1. There should be no overlap in the # tiles of lock and key grids.
  2. There can be space left between the lock and key columns. They don’t have to be an exact fit.

We need to find the count of keys that can fit each input lock. The answer should be the count of unique lock and keys that fit together.

Solution

While the problem statement stated representing the keys with the height of their # tiles, I instead represented it with the height of its . tiles. So in the above exmaple, while the problem statement would represent it as (5,0,2,1,3), I instead represented it as (0,5,3,4,2). I did this to make comparing the key and lock heights easily. If the height of the key is less than the lock, that means there is an overlap and the key and lock do not fit together.

First, lets write a function to convert a given grid to its lock or key representation in height so its easier to process later.

func processPattern(input []string) (heights []int, isKey bool) {
	switch input[0][0] {
	case '.':
		// this is a key
		isKey = true
		for i := 0; i < len(input[0]); i++ {
			for j := 1; j < len(input); j++ {
				if input[j][i] == '#' {
					heights = append(heights, j-1)
					break
				}
			}
		}
	case '#':
		// this is a lock
		for i := 0; i < len(input[0]); i++ {
			for j := 1; j < len(input); j++ {
				if input[j][i] == '.' {
					heights = append(heights, j-1)
					break
				}
			}
		}
	}
	return
}

To check if a lock and key fit together, we will use the logic stated above. If the height of key is less than the height of lock, then there is an overlap and the keys don’t fit together. If all key heights is equal or more than respective lock heights, then they can fit together.

func isLockAndKeyFit(lock, key []int) bool {
	for index, lockHeight := range lock {
		if key[index] < lockHeight {
			return false
		}
	}
	return true
}

Now, we can iterate over all each lock and check if it fits with any of the input keys. If it does, we can increase the final count.

func checkAllLockAndKeys(locks, keys [][]int) int {
	count := 0
	for _, lock := range locks {
		for _, key := range keys {
			if isLockAndKeyFit(lock, key) {
				count++
			}
		}
	}
	return count
}

And that gives us the answer to Part 1. You can find my final code here.

Part 2

If you have solved all other days completely for the rest of the days, you just need to click the button to Deliver the Chronicle collect your last star, the 50th one!

Part 2 and ans

And that’s it. We’re done with Advent of Code 2024, super fun!

An easy day to finish the puzzle streaks. I had a lot of fun solving all the puzzles for this year, thanks Eric for another year of AOC! As always, I am grateful for the extremely helpful community around this event that makes it so much more enjoyable. There are so many smart folks that come up with such unique solutions to these puzzles, notice patterns and use their language’s strengths to find interesting solutions. A huge shoutout to the Golang Insiders community on twitter created by Matt for being such an active community solving these puzzles, sharing their solutions and actively discussing solutions and helping others!

That’s all from me this year. Hope y’all have a brilliant 2025! As always, you can reach out to me on TwitterBluesky or on e-mail at contact[at]shraddhaag[dot]dev.