Coder Social home page Coder Social logo

eduherminio / aochelper Goto Github PK

View Code? Open in Web Editor NEW
55.0 4.0 8.0 204 KB

Helper .NET library for solving Advent of Code puzzles

Home Page: https://adventofcode.com

License: MIT License

C# 100.00%
advent-of-code aoc adventofcode advent puzzles advent-of-code-2021 aoc2021 adventofcode2021 advent-of-code-2022 adventofcode2022

aochelper's Introduction

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

  • Add AoCHelper NuGet package to your project.
  • Create one class per day/problem, using one of the following approaches:
    • Name them DayXX or Day_XX and make them inherit BaseDay.
    • Name them ProblemXX or Problem_XXand make them inherit BaseProblem.
  • Put your input files under Inputs/ directory and follow XX.txt naming convention for day XX. Make sure to copy those files to your output folder.
  • Choose your solving strategy in your Main() method, adjusting it with your custom Action<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 a BaseProblem. 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 to Assembly.GetEntryAssembly(), which assumes the problems are in the same project where Solver 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 different XX 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.
  • [Not recommended] Override InputFilePath in any specific problem class to point to a concrete file. This will make the values of ClassPrefix, InputFileDirPath and InputFileExtension and the implementation of CalculateIndex() irrelevant (see the current implementation).

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:

  • 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>.

aochelper's People

Contributors

codemonkey85 avatar dependabot[bot] avatar eduherminio avatar github-actions[bot] avatar jetersen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

aochelper's Issues

Part 1 Timer seemingly starting early

For some reason, the Part 1 for everything is taking much longer than part 2 of the same question. For example:

image

I am not sure why this is the case. For Day 1, part 1 is doing significantly less than part 2. For Day 2, both parts are the exact same. Could this be related to how I have written my parts or is this something related to when AoCHelper starts the timer? This may also be a case of me not entirely understanding how the Helper is supposed to work.

Please note, I am using the Template that is linked in the main Readme.

Here is an example of how my Day 2 is set up:

    public class Day_02 : BaseDay
    {
        private readonly string _input;

        public Day_02()
        {
            _input = File.ReadAllText(InputFilePath);
        }

        public override ValueTask<string> Solve_1() => Part1();

        public override ValueTask<string> Solve_2() => Part2();

        private ValueTask<string> Part1()
        {
            throw new System.NotImplementedException();
        }

        private ValueTask<string> Part2()
        {
            throw new System.NotImplementedException();
        }
    }

Solves in reverse order

Using Solver.SolveAll(); will result in a reverse order, and somehow a duplicate being printed, as seen below:

This is my folder structure:

It looks like this issue is related to #137, but I'm not sure why this happens in my case.

Solve problem by index

Add an option to solve a problem my index.

Example:
Solver.Solve(12) should solve problem(s) where CalculateIndex() returns 12.

This should facilitate the parsing of arguments from standard input (idea taken from here, thanks @ZeevoX!).


Once the functionality is implemented, it'd be nice to provide something out of the box in the template.

[Enhancement] Timing for day construction

I think it might be useful to (optionally?) allow to capture the timings of the day constructors. Day 7 of 2020, had a lot of up front processing that both parts leveraged. instead of doing it twice, it makes sense to put in the constructor. However doing so, the Part 1 and Part 2 become a lot slimmer just leveraging the data structures built by the constructor, and I think this results in artificially low runtimes, since the bulk of the processing wasn't accounted for.

Solver without static context?

Would be nice if I could dependency inject the solver.

What you've done in your pull.ps1 I have done in C# by injecting a http client.

Exceptions that contain brackets break the console

Hi :-)
When I run my project using SolveAll in Debug mide, all is well and I get a nice pribntout of the 7 days so far.
Using release more, however, trips at day 3:
image

I think this happens when my code throws an exception and then the exception message and stack trace contain brackets []
the console format thing assumes special meaning so I suppose you need to escape those brackets before sending them into the console.

Possibility of testing small demo inputs

Hi,
Thanks for this great tool ! I am using it again this year.

I have a mix between a feature request / question :
I'd like to implement some tests, but not using my own input files, but the small examples that is provided for each question (let's call them demo inputs).
As of now, I have to switch the inputs, but it is very redundant between each part and all my typos ^^'.

I suppose writing a Tests folder that take "test" inputs would be the best, but that mean I need to override by hand each BaseDay just to override InputFileDirPath so that it is the demo input that is used for testing.

Do you think that could be an added feature, or do you see a better way to do it ?

Ability to do multiple years

I've taken the idea of your framework and expanded on it by allowing for multiple years.

My updated project structure is as follows:

+---AdventOfCode
|   AdventOfCode.csproj
|   GlobalUsings.cs
|   Program.cs
|
+---2015
|   |   Day_01.cs
|   |   Day_02.cs
|   |   Day_03.cs
|   |
|   \---Inputs
|           01.txt
|           02.txt
|           03.txt
|
+---2021
    |   Day_01.cs
    |   Day_02.cs
    |   Day_03.cs
    |
    \---Inputs
            01.txt
            02.txt
            03.txt

SolverConfiguration.ClearConsole doesn't work properly

SolverConfiguration.ClearConsole doesn't work properly.

More specifically, it doesn't work at least when the output to clear is big (i.e. you've solved a bunch of days or are using SolverConfiguration.ShowConstructorElapsedTime or/and SolverConfiguration.ShowTotalElapsedTimePerDay), but sometimes in other scenarios as well.

It doesn't matter what combination of Console.Clear() and/or AnsiConsole.Console.Clear(true) is used, but I can't find a way to fully clear the output of previous runs.

Back buffer rendering technique mentioned in spectreconsole/spectre.console#156 to re-render the table doesn't fix this issue either.

Clear Console happens regardless of flag

Regardless if I pass true or false for ClearConsole, it clears anyways. Looking at the code here, it seems it will do a clear no matter what, just either a Console.Clear or an AnsiConsole Clear.

I'd like to be able to use Console.WriteLine (or AnsiConsole.WriteLine) for debugging and not have those lines wiped out by the results.

image

Problems being solved backwards order

I added a Day02.cs today, and tried SolveLast() but it ran Day01 again. Running Solver.SolveAll() results in this output:

image

As far as I can tell the SolveAll() relies on LoadAllProblems() which just scans the assembly for classes that extend BaseDay but doesn't sort them? Unsure how to resolve this on my side, hoping you have some ideas (or I'm doing something wrong).

Project layout:
image

Config option to allow for multiple runs

Would be nice if we could set a config property that would run each solution N number of times and take the average timing across those runs. Where N is the value set in config.

            SolverConfiguration cfg = new();
            cfg.RunCount = 20;
            Solver.SolveAll(cfg);

IOException thrown by Solver.SolveLast when debugging in VS Code

Just installed AocHelper and using the Template. When attempting to debug my code, the SolveLast method throws an IOException when attempting to set the cursor visibility.
image

This project has run successfully when not using the debugger.
This same code, when debugged using Visual Studio, will run just fine (debugger behaves without throwing the exception).

I suspect this is some configuration or installation problem on my end with VSCode. Have you seen anything like this before?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.