01020304050607080910111213141516171819202122232425

Advent of Code

2024/4

Ceres Search

in C#

by encse

"Looks like the Chief's not here. Next!" One of The Historians pulls out a device and pushes the only button on it. After a brief flash, you recognize the interior of the Ceres monitoring station! As the search for the Chief continues, a small Elf who lives on the station tugs on your shirt; she'd like to know if you could help her with her word search. She only has to find one word: XMAS.

Visit the website for the full story and puzzle description.

I employed my proven tactic of converting the input into a dictionary, using coordinates as keys. This approach makes it straightforward to iterate over the keys and check whether they fall within the bounds of the map.

Representing coordinates with complex numbers is another effective technique for handling steps in various directions.

The algorithm itself is a straightforward brute-force check of all starting positions and reading orders.

namespace AdventOfCode.Y2024.Day04;

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Numerics;
using System.Linq;

using Map = System.Collections.Immutable.ImmutableDictionary<System.Numerics.Complex, char>;

[ProblemName("Ceres Search")]
class Solution : Solver {

    Complex Up = -Complex.ImaginaryOne;
    Complex Down = Complex.ImaginaryOne;
    Complex Left = -1;
    Complex Right = 1;

    public object PartOne(string input) {
        var mat = GetMap(input);
        return (
            from pt in mat.Keys
            from dir in  new[] { Right, Right + Down, Down + Left, Down}
            where Matches(mat, pt, dir, "XMAS")
            select 1
        ).Count();
    }

    public object PartTwo(string input) {
        var mat = GetMap(input);
        return (
            from pt in mat.Keys
            where 
                Matches(mat, pt + Up + Left, Down + Right, "MAS") && 
                Matches(mat, pt + Down + Left, Up + Right, "MAS")
            select 1
        ).Count();
    }

    // check if the pattern (or its reverse) can be read in the given direction 
    // starting from pt
    bool Matches(Map map, Complex pt, Complex dir, string pattern) {
        var chars = Enumerable.Range(0, pattern.Length)
            .Select(i => map.GetValueOrDefault(pt + i * dir))
            .ToArray();
        return
            Enumerable.SequenceEqual(chars, pattern) ||
            Enumerable.SequenceEqual(chars, pattern.Reverse());
    }

    // store the points in a dictionary so that we can iterate over them and 
    // to easily deal with points outside the area using GetValueOrDefault
    Map GetMap(string input) {
        var map = input.Split("\n");
        return (
            from y in Enumerable.Range(0, map.Length)
            from x in Enumerable.Range(0, map[0].Length)
            select new KeyValuePair<Complex, char>(Complex.ImaginaryOne * y + x, map[y][x])
        ).ToImmutableDictionary();
    }
}

Please ☆ my repo if you like it!

© 2025 Advent of Code is a registered trademark in the US Images provided by Bing image creator