Home

Awesome

AoCHelper

GitHub Actions Nuget

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:

aochelper

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

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):

Advanced usage

You can also:

Testing

Usage examples

Example projects can be found at:

Some cool repositories that add their own abstractions/customizations on top of AocHelper:

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:

* Consider enabling ShowConstructorElapsedTime and ShowTotalElapsedTimePerDay in Action<SolverConfiguration>.