Unlocking the North Pole: Solving Advent of Code Day 1
02 Dec 2025 #csharpBack in 2022, I challenged myself with a different kind of Advent project.
Instead of running an Advent of Code, I ran an Advent of Posts. I wrote 22 posts in the days before Christmas. I missed two days but I declared the mission complete.
This year, I’m following the Advent of Code. I’d like to challenge myself to write “functionalish” solutions.
Here are the instructions for Day 1 and my solution:
Opening the secret entrance to the North Pole
Since there are only two rotations: left and right, I’m creating a discriminated union-like hierarchy. And I’m writing a separate class for the dial itself.
abstract record Rotation
{
public record Left(int Distance) : Rotation;
public record Right(int Distance) : Rotation;
}
record Dial(int Position)
{
public Dial Turn(Rotation rotation)
{
return rotation switch
{
Rotation.Left f => this with { Position = (Position - f.Distance)%100 },
Rotation.Right r => this with { Position = (Position + r.Distance)%100 },
_ => throw new NotImplementedException(),
};
}
}
So far, I could do:
var d = new Dial(11);
d.Turn(new Rotation.Right(8)).Turn(new Rotation.Left(19))
// [Dial { Position = 0 }]
I have to confess, figuring out the modulus operation to move the dial took me a while.
With the dial rotating, the only missing piece is applying rotations and counting zeros,
static class Password
{
public static int Find(Dial d, IEnumerable<Rotation> rotations)
{
var state = rotations.Aggregate((Dial: d, Password: 0), (state, rotation) =>
{
var dial = state.Dial.Turn(rotation);
var pwd = dial.Position == 0 ? state.Password + 1: state.Password;
return (dial, pwd);
});
return state.Password;
}
}
I’m using LINQ Aggregate method to turn the dial and count the zeros.
That works, but Copilot and others’ solutions showed me a cleaner approach: separating moving the dial and counting with Scan(),
static class Password
{
public static int Find(Dial d, IEnumerable<Rotation> rotations)
{
return rotations.Scan(d, (dial, rotation) => dial.Turn(rotation))
.Count(d => d.Position == 0);
}
public static IEnumerable<TAccumulate> Scan<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
var acc = seed;
yield return acc;
foreach (var item in source)
{
acc = func(acc, item);
yield return acc;
}
}
}
And here’s the full solution:
var dial = new Dial(50);
var rotations = new Rotation[]
{
new Rotation.Left(68),
new Rotation.Left(30),
new Rotation.Right(48),
new Rotation.Left(5),
new Rotation.Right(60),
new Rotation.Left(55),
new Rotation.Left(1),
new Rotation.Left(99),
new Rotation.Right(14),
new Rotation.Left(82)
};
var pwd = Password.Find(dial, rotations);
Console.WriteLine(pwd);
Console.ReadLine();
abstract record Rotation
{
public record Left(int Distance) : Rotation;
public record Right(int Distance) : Rotation;
}
record Dial(int Position)
{
public Dial Turn(Rotation rotation)
{
return rotation switch
{
Rotation.Left f => this with { Position = (Position - f.Distance)%100 },
Rotation.Right r => this with { Position = (Position + r.Distance)%100 },
_ => throw new NotImplementedException(),
};
}
}
static class Password
{
public static int Find(Dial d, IEnumerable<Rotation> rotations)
{
return rotations.Scan(d, (dial, rotation) => dial.Turn(rotation))
.Count(d => d.Position == 0);
}
public static IEnumerable<TAccumulate> Scan<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
var acc = seed;
yield return acc;
foreach (var item in source)
{
acc = func(acc, item);
yield return acc;
}
}
}
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.