Advent of Code 2024 - Day 4
Ceres Search
December 19th, 2024
This is where I thought things were starting to get interesting. It took a little bit more thinking and some tinkering to get the solution right, but it worked out in the end.
# Part 1
This is basically just a word search at the most basic level. We have some X by Y grid of letters containing only Xs, Ms, As, and Ss, and we have to find the number of occurrences of the word “XMAS” in the grid. The word can be found in any direction, backwards, and can even overlap with other occurrences. The following is an example of a grid:
And here's the same thing but letters not involved with any XMASes are replaced with periods. There are 18 occurrences total in this example:
It took a little bit for me to figure this out. I knew that the most straightforward method would be to use some sort of graph data structure to represent the grid and then search for all occurrences, but figuring out the specific algorithm was a little tricky. However, I realized that:
- All the instances start with X, meaning we can search for Xs only initially to find the possible word roots.
- From there, the direction of possible valid instances is set by all adjacent Ms that neighbour all root Xs.
- Finally, we know what neighbours must come sequentially, so we can just search down that direction to determine if we found a valid instance of XMAS.
To implement this, I created a class to represent a node. Within each class is a hash table of pointers to all adjacent nodes, where the key is the direction of the adjacent node relative to the current node.
We can then read in the file to assemble the graph—first by creating all the nodes, then linking them together by assigning the appropriate pointers.
After that, implementation of the search algorithm using a semi-breadth first search was pretty straight forward. We search for all Xs, then all neighbouring Ms of those Xs (keeping track of the direction). Then, we look down all possible directions (based on the neighbours we found) to see if we have a valid instance of XMAS.
The result is this final implementation:
# Part 2
This second part gets a little trickier as now we're trying to look for “X-MAS”es instead, the distinction being that an X-MAS is an X made of two MASes, like shown below:
We can use a similar line of reasoning as before to solve this part. We search for all the As as the roots this time (since there's always an A in the middle of an X-MAS), then look for neighbouring Ms. From there, each neighbouring M must have an opposing S relative to the root A. If a given root has two such pairs, it's a valid X-MAS. This leads to the following modified search function:
And the final implementation for part 2:
Definitely starting to get a little trickier now, but I'm still enjoying the challenge. There's some kind of charm with these particular questions that you don't get with LeetCode problems and the like and I wish I had done this sooner. Here's hoping that I fair just as well with the other problems.