diff --git a/AdventOfCode.lpi b/AdventOfCode.lpi
index 64a32e1..646efc6 100644
--- a/AdventOfCode.lpi
+++ b/AdventOfCode.lpi
@@ -37,6 +37,10 @@
+
+
+
+
diff --git a/AdventOfCode.lpr b/AdventOfCode.lpr
index d3d63eb..c5c3607 100644
--- a/AdventOfCode.lpr
+++ b/AdventOfCode.lpr
@@ -24,6 +24,7 @@ uses
cthreads,
{$ENDIF}
Classes, SysUtils, CustApp,
+ USolver,
UTrebuchet, UCubeConundrum;
type
@@ -44,10 +45,14 @@ type
{ TAdventOfCode }
procedure TAdventOfCode.RunPuzzleSolutions;
+var
+ engine: TSolverEngine;
begin
WriteLn('### Advent of Code 2023 ###');
TTrebuchet.Run;
TCubeConundrum.Run;
+ engine := TSolverEngine.Create;
+ engine.Free;
end;
procedure TAdventOfCode.DoRun;
diff --git a/USolver.pas b/USolver.pas
new file mode 100644
index 0000000..a5e0de9
--- /dev/null
+++ b/USolver.pas
@@ -0,0 +1,138 @@
+{
+ Solutions to the Advent Of Code.
+ Copyright (C) 2023 Stefan Müller
+
+ This program is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program. If not, see .
+}
+
+unit USolver;
+
+{$mode ObjFPC}{$H+}
+{$interfaces corba}
+
+interface
+
+uses
+ Classes, SysUtils;
+
+type
+
+ { ISolver }
+
+ ISolver = interface
+ procedure Init;
+ procedure ProcessDataLine(const ALine: string);
+ procedure Finish;
+ procedure Free;
+ function GetDataFileName: string;
+ function GetPuzzleName: string;
+ function GetResultPart1: Integer;
+ function GetResultPart2: Integer;
+ property DataFileName: string read GetDataFileName;
+ property PuzzleName: string read GetPuzzleName;
+ property ResultPart1: Integer read GetResultPart1;
+ property ResultPart2: Integer read GetResultPart2;
+ end;
+
+ { TSolver }
+
+ TSolver = class abstract(ISolver)
+ protected
+ FPart1, FPart2: Integer;
+ public
+ procedure Init; virtual;
+ procedure ProcessDataLine(const ALine: string); virtual; abstract;
+ procedure Finish; virtual; abstract;
+ procedure Free; virtual;
+ function GetDataFileName: string; virtual; abstract;
+ function GetPuzzleName: string; virtual; abstract;
+ function GetResultPart1: Integer; virtual;
+ function GetResultPart2: Integer; virtual;
+ end;
+
+ { TSolverEngine }
+
+ TSolverEngine = class
+ private
+ procedure ProcessData(constref ASolver: ISolver);
+ public
+ procedure Run(constref ASolver: ISolver);
+ procedure RunAndFree(constref ASolver: ISolver);
+ end;
+
+implementation
+
+{ TSolver }
+
+procedure TSolver.Init;
+begin
+ FPart1 := 0;
+ FPart2 := 0;
+end;
+
+procedure TSolver.Free;
+begin
+ Free;
+end;
+
+function TSolver.GetResultPart1: Integer;
+begin
+ Result := FPart1;
+end;
+
+function TSolver.GetResultPart2: Integer;
+begin
+ Result := FPart2;
+end;
+
+{ TSolverEngine }
+
+procedure TSolverEngine.ProcessData(constref ASolver: ISolver);
+var
+ data: TextFile;
+ s: string;
+begin
+ ASolver.Init;
+
+ AssignFile(data, ConcatPaths(['data', ASolver.DataFileName]));
+ try
+ reset(data);
+ while (not EOF(data)) do
+ begin
+ readln(data, s);
+ ASolver.ProcessDataLine(s);
+ end;
+ finally
+ CloseFile(data)
+ end;
+
+ ASolver.Finish;
+end;
+
+procedure TSolverEngine.Run(constref ASolver: ISolver);
+begin
+ WriteLn;
+ WriteLn('--- ', ASolver.PuzzleName, ' ---');
+ ProcessData(ASolver);
+ WriteLn('Part 1: ', ASolver.ResultPart1);
+ WriteLn('Part 2: ', ASolver.ResultPart2);
+end;
+
+procedure TSolverEngine.RunAndFree(constref ASolver: ISolver);
+begin
+ Run(ASolver);
+ ASolver.Free;
+end;
+
+end.
+