I originally posted this post on my blog.
This year, I'm following the Advent of Code. I challenged myself to write "functionalish" solutions. Here's one of the puzzles I've liked the most.
On Day 7 of Advent of Code, we're studying tachyon beams while we're stuck in a teleporter.
We're stuck in a teleporter because we've been trying to help the elves with all the Christmas preparation. But each step has complicated things even more, making it a mission impossible. I feel like in an episode of The Mandalorian. But anyway, back to code...
I imagine this puzzle as a game where each iteration moves the beam until it hits the end of the manifold.
Here's my solution.
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);
A manifold is an array of array of strings. Each cell could be an empty space or a splitter.
Like this,
var manifold = new string[][]
{
[ ".", ".", "S", ".", "." ],
[ ".", ".", ".", ".", "." ],
[ ".", ".", "^", ".", "." ],
[ ".", ".", ".", ".", "." ]
};
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 create HasReachedTheEnd() to move the beam on its own, like this,
var beam = Start(manifold);
while (!HasReachedTheEnd(manifold, beam))
{
beam = Move(manifold, beam);
}
The next step is to count when a beam splits. I do that inside Move().
And here's my full solution. (We're supposed to parse the input manifold. But I'm lazy, so I'm harcoding a sample input.)
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.
Top comments (1)
Great resolution, that advent of coding. I, however, tend to distrust so lengthy exercises, after my experience in HackerRank. Great solution BTW !