AoCHelper 4.0.0
dotnet add package AoCHelper --version 4.0.0
NuGet\Install-Package AoCHelper -Version 4.0.0
<PackageReference Include="AoCHelper" Version="4.0.0" />
paket add AoCHelper --version 4.0.0
#r "nuget: AoCHelper, 4.0.0"
// Install AoCHelper as a Cake Addin #addin nuget:?package=AoCHelper&version=4.0.0 // Install AoCHelper as a Cake Tool #tool nuget:?package=AoCHelper&version=4.0.0
AoCHelper
AoCHelper is a support library for solving Advent of Code puzzles, available for .NET and .NET Standard 2.x.
It provides a 'framework' so that you only have to worry about solving the problems, and measures the performance of your solutions.
Problem example:
using AoCHelper;
using System.Threading.Tasks;
namespace AdventOfCode;
public class Day_01 : BaseDay
{
public override ValueTask<string> Solve_1() => new("Solution 1");
public override ValueTask<string> Solve_2() => new("Solution 2");
}
Output example:
AdventOfCode.Template
Creating your Advent of Code repository from AdventOfCode.Template is the quickest way to get up and running with AoCHelper
.
There's also AdventOfCode.MultiYearTemplate available of you want to keep all the years in the same repository, but I'd recommend to use the former one if you're participating in Advent of Code or using AoCHelper for the first time.
Simple usage
- Add AoCHelper NuGet package to your project.
- Create one class per day/problem, using one of the following approaches:
- Name them
DayXX
orDay_XX
and make them inheritBaseDay
. - Name them
ProblemXX
orProblem_XX
and make them inheritBaseProblem
.
- Name them
- Put your input files under
Inputs/
directory and followXX.txt
naming convention for dayXX
. Make sure to copy those files to your output folder. - Choose your solving strategy in your
Main()
method, adjusting it with your customAction<SolverConfiguration>
if needed:Solver.SolveAll();
Solver.SolveLast();
Solver.SolveLast(opt => opt.ClearConsole = false);
Solver.Solve<Day_05>();
Solver.Solve(new List<uint>{ 5, 6 });
Solver.Solve(new List<Type> { typeof(Day_05), typeof(Day_06) });
Customization
A custom Action<SolverConfiguration>
can be provided to any of the Solver
methods. It has the following configurable options (false
or null
by default unless otherwise specified):
bool ClearConsole
: Clears previous runs information from the console. True by default.bool ShowOverallResults
: Shows a panel at the end of the run with aggregated stats of the solved problems. True by default when solving multiple problems, false otherwise.bool ShowConstructorElapsedTime
: Shows the time elapsed during the instantiation of aBaseProblem
. This normally reflects the elapsed time while parsing the input data.bool ShowTotalElapsedTimePerDay
: Shows total elapsed time per day. This includes constructor time + part 1 + part 2.string? ElapsedTimeFormatSpecifier
: Custom numeric format strings used for elapsed milliseconds. See Standard numeric format strings.List<Assembly>
: Assembly/Assemblies where the problems are located. Defaults toAssembly.GetEntryAssembly()
, which assumes the problems are in the same project whereSolver
is invoked.
Advanced usage
You can also:
- Create your own abstract base class tha(t inherits
BaseProblem
, make all your problem classes inherit it and use this custom base class to:- Override
ClassPrefix
property, to be able to follow your own$(ClassPrefix)XX
or$(ClassPrefix)_XX
convention in each one of your problem classes. - Override
InputFileDirPath
to change the input files directory - Override
InputFileExtension
to change the input files extension. - Override
CalculateIndex()
to follow a differentXX
or_XX
convention in your class names. - Override
InputFilePath
to follow a different naming convention in your input files. Check the current implementation to understand how to reuse all the other properties and methods.
- Override
- [Not recommended] Override
InputFilePath
in any specific problem class to point to a concrete file. This will make the values ofClassPrefix
,InputFileDirPath
andInputFileExtension
and the implementation ofCalculateIndex()
irrelevant (see the current implementation).
Testing
- Example of simple AoC solutions testing: SampleTests
- Example of advanced AoC solutions testing by providing a custom input test filepath: ModifyInputFilePathTests_SampleTests
- Example of advanced AoC solutions testing by providing a custom input test dir path: ModifyInputFileDirPath_SampleTests
Usage examples
Example projects can be found at:
- AoC2023 (v3.x)
- AoC2022 (v2.x)
- AoC2021 (v1.x)
- AdventOfCode.Template
- AoCHelper.PoC
- AoCHelper.Test
- AoC2020 (v0.x)
- All these repositories
Some cool repositories that add their own abstractions/customizations on top of AocHelper
:
- RachaelBooth/AdventOfCode2022:
BaseSolver<U>
andBaseSolver<U, V>
wrappers aroundBaseProblem
to haveU Solve1()
andV Solve2
methods. - Morphix84/AdventOfCode: input fetching and same-repository-multi-year support.
- codemonkey85/Advent-of-Code-2023: problems located in a library project and
Solver
invoked from both a CLI and a Web project.
v1
to v2+
migration
Methods that accept an instance of SolverConfiguration
were deprecated in v2
and removed in v3
.
They have been replaced by methods that accept Action<SolverConfiguration>
.
v1
:
await Solver.SolveAll(new SolverConfiguration
{
ShowConstructorElapsedTime = true,
ShowOverallResults = true,
ClearConsole = false
});
v2+
:
await Solver.SolveAll(options =>
{
options.ShowConstructorElapsedTime = true;
options.ShowOverallResults = true;
options.ClearConsole = false;
});
v0.x
to v1.x
migration
BaseProblem.Solve_1()
and BaseProblem.Solve_2()
signature has changed: they must return ValueTask<string>
now.
ValueTask<T>
has constructors that accept both T
and Task<T>
, so:
v0.x
:
public class Day_01 : BaseDay
{
public override string Solve_1() => "Solution 2";
public override string Solve_2() => FooAsync().Result;
private async Task<string> FooAsync()
{
await Task.Delay(1000);
return "Solution 2";
}
}
becomes now in v1.x
:
public class Day_01 : BaseDay
{
public override ValueTask<string> Solve_1() => new("Solution 2");
public override ValueTask<string> Solve_2() => new(FooAsync());
private async Task<string> FooAsync()
{
await Task.Delay(1000);
return "Solution 2";
}
}
or in case we prefer async
/await
over returning the task, as recommended here:
public class Day_01 : BaseDay
{
public override ValueTask<string> Solve_1() => new("Solution 2");
public override async ValueTask<string> Solve_2() => new(await FooAsync());
private async Task<string> FooAsync()
{
await Task.Delay(1000);
return "Solution 2";
}
}
Tips
Your problem/day classes are instantiated only once, so parsing the input file (InputFilePath
) in your class constructor allows you to:
- Avoid executing parsing logic twice per problem.
- Measure more accurately your part 1 and part 2 solutions performance*.
* Consider enabling ShowConstructorElapsedTime
and ShowTotalElapsedTimePerDay
in Action<SolverConfiguration>
.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Spectre.Console (>= 0.49.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
.NETStandard 2.1
- Spectre.Console (>= 0.49.1)
-
net8.0
- Spectre.Console (>= 0.49.1)
-
net9.0
- Spectre.Console (>= 0.49.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
4.0.0 | 4,069 | 11/24/2024 |
3.1.0 | 11,008 | 11/30/2023 |
3.1.0-alpha.1 | 87 | 11/28/2023 |
3.0.0 | 2,648 | 11/24/2023 |
3.0.0-alpha.1 | 80 | 11/20/2023 |
2.0.2 | 1,761 | 12/14/2022 |
2.0.2-alpha.1 | 130 | 12/11/2022 |
2.0.1 | 714 | 12/7/2022 |
2.0.0 | 1,429 | 11/12/2022 |
2.0.0-alpha.1 | 127 | 11/2/2022 |
1.0.2 | 1,932 | 11/29/2021 |
1.0.1 | 363 | 11/17/2021 |
1.0.0 | 359 | 11/16/2021 |
0.15.1 | 522 | 5/2/2021 |
0.15.0 | 800 | 12/16/2020 |
0.14.0 | 905 | 12/6/2020 |
0.13.0 | 471 | 12/4/2020 |
0.12.1 | 494 | 12/3/2020 |
0.11.0 | 516 | 12/2/2020 |
0.10.0 | 560 | 11/29/2020 |
0.9.0 | 457 | 11/29/2020 |
0.8.2 | 399 | 11/28/2020 |
0.8.1 | 414 | 11/28/2020 |
0.8.0 | 440 | 11/28/2020 |
0.7.0 | 407 | 11/26/2020 |
0.7.0-alpha.1 | 238 | 11/25/2020 |
0.6.0 | 425 | 11/24/2020 |
0.5.1 | 424 | 11/12/2020 |
0.5.0 | 499 | 5/3/2020 |
0.5.0-alpha-1 | 363 | 5/3/2020 |
0.4.0 | 514 | 2/29/2020 |
0.3.1 | 519 | 12/6/2019 |
0.3.0 | 514 | 12/6/2019 |
0.2.3 | 520 | 12/3/2019 |
0.2.2 | 533 | 12/3/2019 |
0.2.1 | 518 | 12/3/2019 |
0.2.0 | 502 | 12/2/2019 |
0.1.0 | 494 | 12/2/2019 |
0.1.0-alpha | 400 | 11/29/2019 |