Added solution for "Day 5: If You Give A Seed A Fertilizer", part 1

This commit is contained in:
Stefan Müller 2023-12-05 14:44:32 +01:00 committed by Stefan Müller
parent 931b4b60f9
commit c9e9eca35a
6 changed files with 309 additions and 2 deletions

View File

@ -49,6 +49,10 @@
<Filename Value="solvers\UScratchcards.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="UGiveSeedFertilizer.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -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;

208
UGiveSeedFertilizer.pas Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
}
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<TAlmanacMapRange>;
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<Cardinal>;
FMaps: specialize TFPGObjectList<TAlmanacMap>;
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<TAlmanacMapRange>.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<Cardinal>.Create;
FMaps := specialize TFPGObjectList<TAlmanacMap>.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.

View File

@ -52,6 +52,10 @@
<Filename Value="UScratchcardsTestCases.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="UGiveSeedFertilizerTestCases.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -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}

View File

@ -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 <http://www.gnu.org/licenses/>.
}
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.