01020304050607080910111213141516171819202122232425

Advent of Code

2024/8

Resonant Collinearity

in C#

by encse

You find yourselves on the roof of a top-secret Easter Bunny installation.

While The Historians do their thing, you take a look at the familiar huge antenna. Much to your surprise, it seems to have been reconfigured to emit a signal that makes people 0.1% more likely to buy Easter Bunny brand Imitation Mediocre Chocolate as a Christmas gift! Unthinkable!

Visit the website for the full story and puzzle description.

Continuing the steps I started yesterday, I extracted a common function (GetUniquePositions) that takes a parameter to generate antinode positions, representing the difference between part one and part two.

getAntinodes returns the antinode positions of srcAntenna on the dstAntenna side. It doesn’t need to be symmetric — i.e., it doesn’t have to return the antinodes on the srcAntenna side — because GetUniquePositions will call it with the parameters swapped as well. This allows us to handle only one direction at a time.

The generators are fairly straightforward: I simply take steps in the direction determined by the antennas, starting from the destination. Since I represented coordinates using complex numbers again, there’s no need for any special handling on the algebra side, regular + and - operations work.

The GetAntinodes delegate is introduced only for documentation purposes. It looks better to my eyes than an ugly Func<> with four type parameters would in GetUniquePositions-s signature.

namespace AdventOfCode.Y2024.Day08;

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

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

[ProblemName("Resonant Collinearity")]
class Solution : Solver {
    public object PartOne(string input) => GetUniquePositions(input, GetAntinodes1).Count();
    public object PartTwo(string input) => GetUniquePositions(input, GetAntinodes2).Count();

    HashSet<Complex> GetUniquePositions(string input, GetAntinodes getAntinodes) {
        var map = GetMap(input);

        var antennaLocations = (
            from pos in map.Keys 
            where char.IsAsciiLetterOrDigit(map[pos])
            select pos
        ).ToArray();

        return (
             from srcAntenna in antennaLocations
             from dstAntenna in antennaLocations
             where srcAntenna != dstAntenna && map[srcAntenna] == map[dstAntenna]
             from antinode in getAntinodes(srcAntenna, dstAntenna, map)
             select antinode
         ).ToHashSet();
    }

    // returns the antinode positions of srcAntenna on the dstAntenna side
    delegate IEnumerable<Complex> GetAntinodes(Complex srcAntenna, Complex dstAntenna, Map map);

    // in part 1 we just look at the immediate neighbour
    IEnumerable<Complex> GetAntinodes1(Complex srcAntenna, Complex dstAntenna, Map map) {
        var dir = dstAntenna - srcAntenna;
        var antinote = dstAntenna + dir;
        if (map.Keys.Contains(antinote)) {
            yield return antinote;
        }
    }

    // in part 2 this becomes a cycle, plus dstAntenna is also a valid position now
    IEnumerable<Complex> GetAntinodes2(Complex srcAntenna, Complex dstAntenna, Map map) {
        var dir = dstAntenna - srcAntenna;
        var antinote = dstAntenna;
        while (map.Keys.Contains(antinote)) {
            yield return antinote;
            antinote += dir;
        }
    }

    // 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>(x - y * Complex.ImaginaryOne, 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