diff --git a/AdventOfCode.lpi b/AdventOfCode.lpi
index 102137f..dea1b1c 100644
--- a/AdventOfCode.lpi
+++ b/AdventOfCode.lpi
@@ -49,6 +49,10 @@
+
+
+
+
diff --git a/AdventOfCode.lpr b/AdventOfCode.lpr
index 43c82a3..51224b5 100644
--- a/AdventOfCode.lpr
+++ b/AdventOfCode.lpr
@@ -25,7 +25,7 @@ uses
{$ENDIF}
Classes, SysUtils, CustApp,
USolver,
- UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards;
+ UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer;
type
@@ -54,6 +54,7 @@ begin
engine := TSolverEngine.Create('data');
engine.RunAndFree(TGearRatios.Create);
engine.RunAndFree(TScratchcards.Create);
+ engine.RunAndFree(TGiveSeedFertilizer.Create);
engine.Free;
end;
diff --git a/UGiveSeedFertilizer.pas b/UGiveSeedFertilizer.pas
new file mode 100644
index 0000000..dc44a6b
--- /dev/null
+++ b/UGiveSeedFertilizer.pas
@@ -0,0 +1,208 @@
+{
+ 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 UGiveSeedFertilizer;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, fgl, USolver;
+
+type
+
+ { TAlmanacMapRange }
+
+ TAlmanacMapRange = class
+ private
+ FDestinationStart, FSourceStart, FSourceEnd, FDifference1, FDifference2: Cardinal;
+ public
+ constructor Create(const ADestinationStart, ASourceStart, ALength: Cardinal);
+ function TryConvert(const AInput: Cardinal; out OOutput: Cardinal): Boolean;
+ end;
+
+ { TAlmanacMap }
+
+ TAlmanacMap = class
+ private
+ FRanges: specialize TFPGObjectList;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ procedure AddMapRange(const ALine: string);
+ function Convert(const AInput: Cardinal): Cardinal;
+ end;
+
+ { TGiveSeedFertilizer }
+
+ TGiveSeedFertilizer = class(TSolver)
+ private
+ FSeeds: specialize TFPGList;
+ FMaps: specialize TFPGObjectList;
+ procedure ProcessSeeds(const ALine: string);
+ public
+ constructor Create;
+ destructor Destroy; override;
+ procedure ProcessDataLine(const ALine: string); override;
+ procedure Finish; override;
+ function GetDataFileName: string; override;
+ function GetPuzzleName: string; override;
+ end;
+
+implementation
+
+{ TAlmanacMapRange }
+
+constructor TAlmanacMapRange.Create(const ADestinationStart, ASourceStart, ALength: Cardinal);
+begin
+ FDestinationStart := ADestinationStart;
+ FSourceStart := ASourceStart;
+
+ // All input values are within Cardinal range, but the calculations might not be.
+ if ASourceStart <= Cardinal.MaxValue - ALength then
+ FSourceEnd := ASourceStart + ALength
+ else
+ FSourceEnd := Cardinal.MaxValue;
+
+ if ADestinationStart >= ASourceStart then
+ begin
+ FDifference1 := ADestinationStart - ASourceStart;
+ FDifference2 := 0;
+ end
+ else begin
+ FDifference1 := 0;
+ FDifference2 := ASourceStart - ADestinationStart;
+ end;
+end;
+
+function TAlmanacMapRange.TryConvert(const AInput: Cardinal; out OOutput: Cardinal): Boolean;
+begin
+ if (FSourceStart <= AInput) and (AInput < FSourceEnd) then
+ begin
+ if FDifference1 > 0 then
+ OOutput := AInput + FDifference1
+ else
+ OOutput := AInput - FDifference2;
+ Result := True;
+ end
+ else begin
+ OOutput := 0;
+ Result := False;
+ end;
+end;
+
+{ TAlmanacMap }
+
+constructor TAlmanacMap.Create;
+begin
+ FRanges := specialize TFPGObjectList.Create;
+end;
+
+destructor TAlmanacMap.Destroy;
+begin
+ FRanges.Free;
+ inherited Destroy;
+end;
+
+procedure TAlmanacMap.AddMapRange(const ALine: string);
+var
+ split: TStringArray;
+begin
+ split := ALine.Split(' ');
+ FRanges.Add(TAlmanacMapRange.Create(StrToDWord(split[0]), StrToDWord(split[1]), StrToDWord(split[2])));
+end;
+
+function TAlmanacMap.Convert(const AInput: Cardinal): Cardinal;
+var
+ range: TAlmanacMapRange;
+begin
+ for range in FRanges do
+ begin
+ if range.TryConvert(AInput, Result) then
+ Exit;
+ end;
+
+ Result := AInput;
+end;
+
+{ TGiveSeedFertilizer }
+
+procedure TGiveSeedFertilizer.ProcessSeeds(const ALine: string);
+var
+ split: TStringArray;
+ i: Integer;
+begin
+ split := Aline.Split(' ');
+ for i := 1 to Length(split) - 1 do
+ begin
+ FSeeds.Add(StrToDWord(split[i]));
+ end;
+end;
+
+constructor TGiveSeedFertilizer.Create;
+begin
+ FSeeds := specialize TFPGList.Create;
+ FMaps := specialize TFPGObjectList.Create;
+end;
+
+destructor TGiveSeedFertilizer.Destroy;
+begin
+ FSeeds.Free;
+ FMaps.Free;
+ inherited Destroy;
+end;
+
+procedure TGiveSeedFertilizer.ProcessDataLine(const ALine: string);
+begin
+ if LeftStr(ALine, 6) = 'seeds:' then
+ ProcessSeeds(ALine)
+ else if RightStr(ALine, 4) = 'map:' then
+ FMaps.Add(TAlmanacMap.Create)
+ else if Aline <> '' then
+ FMaps.Last.AddMapRange(ALine);
+end;
+
+procedure TGiveSeedFertilizer.Finish;
+var
+ seed, value: Cardinal;
+ map: TAlmanacMap;
+begin
+ for seed in FSeeds do
+ begin
+ value := seed;
+ for map in FMaps do
+ begin
+ value := map.Convert(value);
+ end;
+ if (FPart1 = 0) or (value < FPart1) then
+ FPart1 := value;
+ end;
+end;
+
+function TGiveSeedFertilizer.GetDataFileName: string;
+begin
+ Result := 'give_seed_fertilizer.txt';
+end;
+
+function TGiveSeedFertilizer.GetPuzzleName: string;
+begin
+ Result := 'Day 5: If You Give A Seed A Fertilizer';
+end;
+
+end.
+
diff --git a/tests/AdventOfCodeFPCUnit.lpi b/tests/AdventOfCodeFPCUnit.lpi
index 4f20461..6a82f6b 100644
--- a/tests/AdventOfCodeFPCUnit.lpi
+++ b/tests/AdventOfCodeFPCUnit.lpi
@@ -52,6 +52,10 @@
+
+
+
+
diff --git a/tests/AdventOfCodeFPCUnit.lpr b/tests/AdventOfCodeFPCUnit.lpr
index 3aa8ff7..65174d4 100644
--- a/tests/AdventOfCodeFPCUnit.lpr
+++ b/tests/AdventOfCodeFPCUnit.lpr
@@ -3,7 +3,8 @@ program AdventOfCodeFPCUnit;
{$mode objfpc}{$H+}
uses
- Interfaces, Forms, GuiTestRunner, USolver, UBaseTestCases, UGearRatiosTestCases, UScratchcardsTestCases;
+ Interfaces, Forms, GuiTestRunner, USolver, UBaseTestCases, UGearRatiosTestCases, UScratchcardsTestCases,
+UGiveSeedFertilizerTestCases;
{$R *.res}
diff --git a/tests/UGiveSeedFertilizerTestCases.pas b/tests/UGiveSeedFertilizerTestCases.pas
new file mode 100644
index 0000000..4e42cce
--- /dev/null
+++ b/tests/UGiveSeedFertilizerTestCases.pas
@@ -0,0 +1,89 @@
+{
+ 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 UGiveSeedFertilizerTestCases;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, fpcunit, testregistry, USolver, UBaseTestCases, UGiveSeedFertilizer;
+
+type
+
+ { TGiveSeedFertilizerFullDataTestCase }
+
+ TGiveSeedFertilizerFullDataTestCase = class(TEngineBaseTest)
+ protected
+ function CreateSolver: ISolver; override;
+ published
+ procedure TestPart1;
+ procedure TestPart2;
+ end;
+
+ { TGiveSeedFertilizerExampleTestCase }
+
+ TGiveSeedFertilizerExampleTestCase = class(TExampleEngineBaseTest)
+ protected
+ function CreateSolver: ISolver; override;
+ published
+ procedure TestPart1;
+ procedure TestPart2;
+ end;
+
+implementation
+
+{ TGiveSeedFertilizerFullDataTestCase }
+
+function TGiveSeedFertilizerFullDataTestCase.CreateSolver: ISolver;
+begin
+ Result := TGiveSeedFertilizer.Create;
+end;
+
+procedure TGiveSeedFertilizerFullDataTestCase.TestPart1;
+begin
+ AssertEquals(51580674, FSolver.GetResultPart1);
+end;
+
+procedure TGiveSeedFertilizerFullDataTestCase.TestPart2;
+begin
+ AssertEquals(-1, FSolver.GetResultPart2);
+end;
+
+{ TGiveSeedFertilizerExampleTestCase }
+
+function TGiveSeedFertilizerExampleTestCase.CreateSolver: ISolver;
+begin
+ Result := TGiveSeedFertilizer.Create;
+end;
+
+procedure TGiveSeedFertilizerExampleTestCase.TestPart1;
+begin
+ AssertEquals(35, FSolver.GetResultPart1);
+end;
+
+procedure TGiveSeedFertilizerExampleTestCase.TestPart2;
+begin
+ AssertEquals(-1, FSolver.GetResultPart2);
+end;
+
+initialization
+
+ RegisterTest(TGiveSeedFertilizerFullDataTestCase);
+ RegisterTest(TGiveSeedFertilizerExampleTestCase);
+end.