Advent Of Code has been around for ages. It’s one of those things that I’ve always wanted to do, but never managed to get into the groove of. I’d maybe do the first puzzle, maybe even a couple of days, but eventually the time of year would overtake me and it would fall by the wayside.
This year is a little different. We’re currently eight days through, and I’m fully up-to-date with all of the challenges. Full gold stars and everything. This is after coming into it five days late and needing to catch up. The difference has been that I’m not the only person I know who is taking part. AOC has caught on at work and there are people in my immediate network - on my direct team, even - all taking part and talking about it. We even have a private leaderboard[1]. Turns out that friendly competition can be a decent motivator for me!
But how am I actually completing the challenges? This is the “stack” I’m using:
- C# and .NET 8/9. (I didn’t get my environment upgraded to 9 until partway through)
- A mix of VS Code and “full fat” Visual Studio. I keep meaning to try Rider too, now it’s free, but I haven’t yet.
- A .NET Console project for the actual puzzle, and an MSTest project for unit tests.
- A Powershell function to setup my stub project each day.
This last one was actually pretty key. .NET has come a long way recently, and
the CLI tool
is pretty great, but for the first few days I was having to follow process of
around a dozen steps to get the project setup I wanted. It was frustrating. I’ve
included the function below. As much so I can easily copy it to my work laptop
tomorrow as for sharing 😅. Using the function makes getting started as simple as
New-AdventOfCodeProject with optional parameters for the year and day.
I could have gone with JavaScript or something and avoided all that initial palaver
with an npm init -y or similar, but sometimes I feel like I don’t write
enough C# any more; it’s mostly JavaScript at work these days, so AOC is an ideal time
to stretch some neglected muscles. Maybe even some new ones? It would be an ideal
opportunity… Regardless, I’m really enjoying using C# for these.
As far as actual approach, I guess I’m essentially using TDD (Test Driven Development). The description gives you everything you need to create at least one unit test using the sample input and expected answer. Apart from the first couple of puzzles, I’ve started with writing this test before any implementation code. From there it’s a case of writing code to pass that unit test. Once the unit test is passing I add code to my programme to load the input from a text file and pass it to my processing code. Sometimes the real input will throw up edge cases I hadn’t thought of[2] so there will be some rework, but it’s all part of the process.
In terms of structure I usually have 3 files:
-
Program.cs- main application file, does the writing to the console. input.txt- puzzle input.-
Day<whatever>.cs- a class file which does the actual processing.
Within the class file the code is usually along the lines of:
namespace AdventOfCode24Day8;
public class DayEight
{
// Keep a copy of our original puzzle input around
private readonly string[] _originalInput;
// Constructor
public DayEight(string[] input)
{
_originalInput = input;
}
// Part One setup and processing
public int PartOne()
{
// Anything specific to processing part one
// pre-processing the input, etc...
return PuzzleSolvingEntryPoint(_originalInput);
}
// Method that actually kicks off the processing.
// Usually named something more relevant to the puzzle
private static int PuzzleSolvingEntryPoint(input)
{
// ...
}
// Any helper methods, etc
}
This approach has been evolving over the last eight days I’ve been taking part, and will probably keep evolving over the remaining days of Advent. The first few days were definitely a bit more “scrappy”!
On the console, the programme is outputting a welcome and then the answer to each part as I complete it. I could probably get fancier, but one of my goals was to keep things as simple as possible. If it doesn’t take me much time then I’m more likely to stick with it. A very basic console app is perfect for this.
The Elephant in the Room
But what about AI? Couldn’t I get something to solve these puzzles for me? Well, yes, I likely could. I think I’m pretty good at “Prompt Engineering”, so could probably make it happen. But doing so would completely ruin the point of it all for me. I’m not an Anti-AI purist. I think every software engineer should make best use of all the tools they have available to solve the problem in front of them as best they can. If Copilot wants to autocomplete parts of the method I’m writing and it looks like what I was about to type out manually[3] anyway, then I’m hitting the Tab key. But there are certain things I want to do. Solving the problem of the day for Advent Of Code is one of them. So while I’ll accept an autocomplete, I’m not asking the chat for the solution. I’m not heading off to ChatGPT, or Gemini, or something else, to feed the entire puzzle details in to get the answer. It would ruin the fun for me.
But once I’ve solved it and got my two stars for the day? Then I will happily query an LLM about the problem. I’ll compare how it approaches getting to a solution. Usually it takes a bit of iterative prompting to get it onto the right track, but that’s part of the challenge of AI tooling. Yesterday, as I was beginning to read a book on how to write Rust, I threw my C# solution into Claude, to see what an equivalent Rust implementation would look like. It was useful as a learning exercise - and, yes, Claude’s conversion did run successfully and produce the correct answers. I doubt it was an optimal conversion, but it did work.
Equally, I might use an LLM to help me with an “extra assignment” after the puzzle was finished with. Day six had a puzzle that was ripe for a console-based visualisation, so I got to work with Copilot over lunch to bring it to life. You can see the results in a 30 second clip over on Bluesky.
Wrapping Up
I’ll be putting all my solutions on GitHub eventually. A couple already are, but the
rest are spread across multiple different computers right now, and I’d need to add
proper .gitignore files and the like to half of them, so it may take me a
while. I’d also want to post them publicly with a bit of a lag, to prevent spoiling
the answer for anyone.
But yeah, now I’m finally taking part properly I’m enjoying Advent Of Code. A lot. Or maybe I’m enjoying rapidly climbing up our private leaderboard, I don’t know. But if you’ve thought about taking part but just haven’t for whatever reason, I do recommend giving it a shot. Treat it as a bit of no-stakes problem solving. Like Wordle, or the crossword or something. You might enjoy it too. I’ve been enjoying the coding brain-teaser format enough that I bought myself a whole book of them.
Oh, and here’s that PowerShell function I mentioned near the start. It’s simple but long, hence why I put it down here and out of the way:
function New-AdventOfCodeProject {
param (
[int]$Year,
[int]$Day
)
if (-not $PSBoundParameters.ContainsKey('Year')) {
$Year = (Get-Date).Year % 100
}
if (-not $PSBoundParameters.ContainsKey('Day')) {
$Day = [int](Get-Date).Day
}
$projectName = "AdventOfCode${Year}Day${Day}"
$projectPath = "$PWD\$projectName"
$testProjectName = "${projectName}.Test"
$testProjectPath = "$projectPath\$testProjectName"
$fileNumber = Convert-ToInitCase -inputString (Convert-NumberToWords -number $Day)
$testFileName = "Day${fileNumber}Tests.cs"
# Create the new folder
New-Item -ItemType Directory -Path $projectPath
# Change into the new directory
Set-Location -Path $projectPath
# Create a new .NET console project
dotnet new console -n $projectName
# Create a new .NET mstest project
dotnet new mstest -n $testProjectName
# Change into the directory of the test project
Set-Location -Path $testProjectPath
# Add a reference from the test project to the console project
dotnet add reference "..\$projectName\$projectName.csproj"
# Rename the UnitTest1.cs file to Day{fileNumber}Tests.cs
Rename-Item "$testProjectPath\UnitTest1.cs" $testFileName
# Change back to the parent directory
Set-Location -Path $projectPath
# Add empty files to the console project: input.txt, and Day{fileNumber}.cs
New-Item -ItemType File -Path "$projectPath\input.txt"
New-Item -ItemType File -Path "$projectPath\Day${fileNumber}.cs"
# Initialize a git repository
git init
# Copy LICENSE from templates
Copy-Item "$env:USERPROFILE\src\1_templates\MIT.LICENSE" -Destination "$projectPath\LICENSE"
# Copy .gitignore from templates
Copy-Item "$env:USERPROFILE\src\1_templates\dotnet.gitignore" -Destination "$projectPath\.gitignore"
# Add these files to git and commit them. Solution files will be added later.
git add LICENSE .gitignore
git commit -m "initial commit"
# Open VS Code from the project parent directory
code $projectPath
}
# Example usage:
# New-AdventOfCodeProject -Year 2024 -Day 7
function Convert-ToInitCase {
param (
[string]$inputString
)
$words = $inputString -split '\s+'
$initCaseString = $words | ForEach-Object { $_.Substring(0,1).ToUpper() + $_.Substring(1).ToLower() }
return -join $initCaseString
}
# Example usage:
# Convert-ToInitCase -inputString "hello world" # Output: "HelloWorld"
function Convert-NumberToWords {
param (
[int]$number
)
$units = @("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine")
$teens = @("ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen")
$tens = @("", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety")
if ($number -lt 10) {
return $units[$number]
} elseif ($number -lt 20) {
return $teens[$number - 10]
} elseif ($number -lt 100) {
$tensPart = [math]::Floor($number / 10)
$unitsPart = $number % 10
if ($unitsPart -eq 0) {
return $tens[$tensPart]
} else {
return "$($tens[$tensPart])-$($units[$unitsPart])"
}
} else {
throw "Number out of range"
}
}
# Example usage:
# Convert-NumberToWords -number 7 # Output: "seven"
-
I’m currently 5th out of 22, which I don’t think is that bad for having started five days behind the leaders. Only three of us have full stars. ↩︎
-
Like the day I assumed all the numbers involved would fit into an Int32 and then had to make the switch to Int64 after my solution crashed halfway through. ↩︎
-
A lot of the autocomplete prompts I get are code relevant to previous years. Which is a great reminder that you need to be checking the output and suggestions from these things thoroughly. ↩︎
Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.