How I'm Doing Advent Of Code in 2024
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. ā©ļø