The obvious route (to me, anyway) was to create a base class that puzzle solutions could inherit from. Then, I could have a console application that would scan the assembly using reflection for concrete implementations of this class, execute them, and check the answer against a text file.
So, this is the base class I came up with.
public abstract class Solution { protected string[] Input; public abstract string Description { get; } protected Solution() { var nameSpace = GetType().Namespace ?? string.Empty; var parts = nameSpace.Split('.'); var path = parts.Skip(2).Select(s => s.Replace("_", string.Empty)).ToArray(); Input = File.ReadAllLines($"{string.Join(Path.DirectorySeparatorChar, path)}{Path.DirectorySeparatorChar}input.txt"); } public abstract string GetAnswer(); }
The constructor loads the puzzle input file and makes it available to subclasses via the Input field. The Description property is for inheritors to implement to describe the puzzle they are solving. Lastly, surprise surprise, GetAnswer should be used by implementors (i.e. me) to solve the puzzle and return the answer as a string. So far, AoC had only required integer answers but, I've been around the block and kept my options open.
So, apart from some timing code (competitive, see?) and some other things added later, the main console app was:
var solutions = Assembly.GetExecutingAssembly() .GetTypes() .Where(t => t.IsSubclassOf(typeof(Solution)) && ! t.IsAbstract) .OrderBy(t => t.Namespace) .ThenBy(t => t.Name); foreach (var solution in solutions) { var instance = Activator.CreateInstance(solution) as Solution; var answer = instance.GetAnswer(); CheckAnswer(instance.GetType(), answer); }
Where CheckAnswer would look in a text file for a line formatted 2021.5.1: abc meaning that the answer to 2021, December the 5th, part one was abc. If they didn't match, it will throw an exception.
Obviously, when embarking on each puzzle I didn't know the answer. Once I had the correct answer, I added it to the text file. The idea behind this mechanism was to prevent regressions as I anticipated code sharing somewhere down the line.
So, my framework was largely in place, I was having fun and... possibly getting a bit cocky.
