AOC 2024, Day 4: Find the X
I used to do a tonne of word search puzzles as a kid. Advent of Code Day 4 was the same, but this time the search has to be done programmatically. Let’s figure it out!
The below is a guest post by the amazing Shraddha Agrawal.
Part 1
Given multiple lines of text, we have to search for the word XMAS
and return its total count. The word is possible to exist in any direction: horizontally, vertically and diagonally and can be written backwards too! For example, this block of input and its solution with a total of 18 XMAS
s.
Solution
I went for a naive solution of iterating over each index of the input. If the character at the current index is X
, search for MAS
in all eight directions: right, left, up, down, diagonally up right, diagonally up left, diagonally down right and diagonally down left. The characters and indexes to check are visualised below. If any of these are a match, the total count should be increased.
While, there are definitely more elegant ways to check this, I did it quite crudely by hardcoding the above while checking for out of bound. That’s pretty much it, the final count of XMAS
is the answer for part 1. You can find my code here.
Part 2
Arguably, Day 4’s Part 2 was simpler than the previous part. This time, in the same input, we had to count the total number of two MAS
s in the shape of an X. All possible ways of arranging two MAS
in the shape of an X are:
Solution
To solve this, I iterated over the entire input, and if the character at the current index was an A
, I checked if there existed any of the above 4 combinations of M
and S
around it. For each successful match, the count went up by 1. I did it again rather crudely like below:
func checkIndex2(input []string, i, j int) int {
if j < 1 || j > len(input[i])-2 {
return 0
}
// M.M
// .A.
// S.S
if input[i-1][j+1] == byte('M') && input[i-1][j-1] == byte('M') && input[i+1][j-1] == byte('S') && input[i+1][j+1] == byte('S') {
return 1
}
// S.S
// .A.
// M.M
if input[i-1][j+1] == byte('S') && input[i-1][j-1] == byte('S') && input[i+1][j-1] == byte('M') && input[i+1][j+1] == byte('M') {
return 1
}
// M.S
// .A.
// M.S
if input[i-1][j+1] == byte('S') && input[i-1][j-1] == byte('M') && input[i+1][j-1] == byte('M') && input[i+1][j+1] == byte('S') {
return 1
}
// S.M
// .A.
// S.M
if input[i-1][j+1] == byte('M') && input[i-1][j-1] == byte('S') && input[i+1][j-1] == byte('S') && input[i+1][j+1] == byte('M') {
return 1
}
return 0
}
The total count returned is the final answer for part two. You can find my final code here.
And with that, day 4 is done and dusted. There are definitely more efficient and elegant ways to solve this. Some folks made use of image.Point
to find the answer in a couple of lines while others made use of custom grid utilities they had cooked up previously!
If you used other unique solution for this, I’d love to learn from it! Reach out to me on Twitter, Bluesky or on e-mail at contact[at]shraddhaag[dot]dev.