Advent of Code Day 7: Splitting Tachyon Beams

On Day 7 of Advent of Code, we’re studying tachyon beams while we’re stuck in a teleporter.

I imagine this puzzle as a game where each iteration moves the beam until it hits the end of the manifold.

Moving a beam

A Beam is a list of positions in the manifold at a given iteration.

record Position(int X, int Y);
record Beam(IEnumerable<Position> Locations);

Here’s the method to move a beam,

static Beam Move(string[][] manifold, Beam beam)
{
    var newLocations = new HashSet<Position>();

    foreach (var current in beam.Locations)
    {
        var downward = manifold[current.X + 1][current.Y];
        if (downward == ".")
        {
            newLocations.Add(new Position(current.X + 1, current.Y));
        }
        else if (downward == "^")
        {
            newLocations.Add(new Position(current.X + 1, current.Y - 1));
            newLocations.Add(new Position(current.X + 1, current.Y + 1));
        }
    }

    return new Beam(newLocations);
}

After moving a beam, I need the entry position of a beam,

static Beam Start(string[][] manifold)
{
    for (int i = 0; i < manifold[0].Length; i++)
    {
        if (manifold[0][i] == "S")
        {
            return new Beam([new Position(0, i)]);
        }
    }

    return new Beam([]);
}

With those two methods, a beam enters and moves downward,

var start = Start(manifold);
var newPosition = Move(manifold, start);
newPosition = Move(manifold, newPosition);

All that’s left is to count splits and move the beam to the end.

Counting splits

Next, I add the number of splits to Beam and create HasReacheTheEnd().

Here’s my full solution,

var manifold = new string[][]
{
    [ ".", ".", ".", ".", ".", ".", ".", "S", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", "^", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", "^", ".", "^", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", "^", ".", "^", ".", "^", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", "^", ".", "^", ".", ".", ".", "^", ".", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", ".", "^", ".", "^", ".", ".", ".", "^", ".", "^", ".", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", ".", "^", ".", ".", ".", "^", ".", ".", ".", ".", ".", "^", ".", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ],
    [ ".", "^", ".", "^", ".", "^", ".", "^", ".", "^", ".", ".", ".", "^", "." ],
    [ ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "." ]
};

var beam = Start(manifold);
while (!HasReachedTheEnd(manifold, beam))
{
    beam = Move(manifold, beam);
}

Console.WriteLine(beam.SplitCount);
Console.ReadLine();

static Beam Start(string[][] manifold)
{
    for (int i = 0; i < manifold[0].Length; i++)
    {
        if (manifold[0][i] == "S")
        {
            return new Beam(0, [new Position(0, i)]);
        }
    }

    return new Beam(0, []);
}

static bool HasReachedTheEnd(string[][] manifold, Beam beam)
{
    var anyBeam = beam.Locations.First();
    return anyBeam.X >= manifold.Length - 1;
}

static Beam Move(string[][] manifold, Beam beam)
{
    var splits = 0;
    var newLocations = new HashSet<Position>();

    foreach (var current in beam.Locations)
    {
        var downward = manifold[current.X + 1][current.Y];
        if (downward == ".")
        {
            newLocations.Add(new Position(current.X + 1, current.Y));
        }
        else if (downward == "^")
        {
            splits++;

            newLocations.Add(new Position(current.X + 1, current.Y - 1));
            newLocations.Add(new Position(current.X + 1, current.Y + 1));
        }
    }

    return new Beam(beam.SplitCount + splits, newLocations);
}

record Position(int X, int Y);
record Beam(int SplitCount, IEnumerable<Position> Locations);

I thought a “tachyon” was a made-up word until I Googled it. TIL what a tachyon is. Win-win.

Et voilà!

Advent of Code sharpens your coding skills. But coding is more than typing symbols fast. It’s also about teamwork, collaboration, and many skills I share in my book, Street-Smart Coding: 30 Ways to Get Better at Coding. That’s the roadmap I wish I’d known from day one.

Get your copy of Street-Smart Coding here