diff --git a/AdventOfCode.lpi b/AdventOfCode.lpi
index 14849ab..f6ed2ae 100644
--- a/AdventOfCode.lpi
+++ b/AdventOfCode.lpi
@@ -121,6 +121,10 @@
+
+
+
+
diff --git a/AdventOfCode.lpr b/AdventOfCode.lpr
index 483f69d..039cf72 100644
--- a/AdventOfCode.lpr
+++ b/AdventOfCode.lpr
@@ -27,7 +27,7 @@ uses
UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer, UWaitForIt, UCamelCards,
UHauntedWasteland, UNumberTheory, UMirageMaintenance, UPipeMaze, UCosmicExpansion, UHotSprings, UPointOfIncidence,
UParabolicReflectorDish, ULensLibrary, UFloorWillBeLava, UClumsyCrucible, ULavaductLagoon, UAplenty,
- UPulsePropagation;
+ UPulsePropagation, UStepCounter;
type
@@ -89,6 +89,7 @@ begin
18: engine.RunAndFree(TLavaductLagoon.Create);
19: engine.RunAndFree(TAplenty.Create);
20: engine.RunAndFree(TPulsePropagation.Create);
+ 21: engine.RunAndFree(TStepCounter.Create);
end;
engine.Free;
diff --git a/solvers/UStepCounter.pas b/solvers/UStepCounter.pas
new file mode 100644
index 0000000..0a86095
--- /dev/null
+++ b/solvers/UStepCounter.pas
@@ -0,0 +1,173 @@
+{
+ 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 UStepCounter;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, Generics.Collections, USolver;
+
+type
+ TPoints = specialize TList;
+
+ { TStepCounter }
+
+ TStepCounter = class(TSolver)
+ private
+ FLines: TStringList;
+ FWidth, FHeight, FMaxSteps: Integer;
+ function FindStart: TPoint;
+ function IsInBounds(constref APoint: TPoint): Boolean;
+ function GetPosition(constref APoint: TPoint): Char;
+ procedure SetPosition(constref APoint: TPoint; const AValue: Char);
+ public
+ property MaxSteps: Integer read FMaxSteps write FMaxSteps;
+ constructor Create;
+ destructor Destroy; override;
+ procedure ProcessDataLine(const ALine: string); override;
+ procedure Finish; override;
+ function GetDataFileName: string; override;
+ function GetPuzzleName: string; override;
+ end;
+
+const
+ CStartChar = 'S';
+ CPlotChar = '.';
+ CTraversedChar = '+';
+ CDirections: array of TPoint = ((X: 1; Y: 0), (X: -1; Y: 0), (X: 0; Y: 1), (X: 0; Y: -1));
+
+implementation
+
+{ TStepCounter }
+
+function TStepCounter.FindStart: TPoint;
+var
+ i, j: Integer;
+begin
+ for i := 1 to FWidth do
+ for j := 0 to FHeight - 1 do
+ if FLines[j][i] = CStartChar then
+ begin
+ Result.X := i;
+ Result.Y := j;
+ Exit;
+ end;
+end;
+
+function TStepCounter.IsInBounds(constref APoint: TPoint): Boolean;
+begin
+ Result := (0 < APoint.X) and (APoint.X <= FWidth) and (0 <= APoint.Y) and (APoint.Y < FHeight);
+end;
+
+function TStepCounter.GetPosition(constref APoint: TPoint): Char;
+begin
+ Result := FLines[APoint.Y][APoint.X];
+end;
+
+procedure TStepCounter.SetPosition(constref APoint: TPoint; const AValue: Char);
+var
+ s: string;
+begin
+ s := FLines[APoint.Y];
+ s[APoint.X] := AValue;
+ FLines[APoint.Y] := s;
+end;
+
+constructor TStepCounter.Create;
+begin
+ FMaxSteps := 64;
+ FLines := TStringList.Create;
+end;
+
+destructor TStepCounter.Destroy;
+begin
+ FLines.Free;
+ inherited Destroy;
+end;
+
+procedure TStepCounter.ProcessDataLine(const ALine: string);
+begin
+ FLines.Add(ALine);
+end;
+
+procedure TStepCounter.Finish;
+var
+ currentStep: Integer;
+ currentPlots, nextPlots, temp: TPoints;
+ plot, direction, next: TPoint;
+ //s: string;
+begin
+ FWidth := Length(FLines[0]);
+ FHeight := FLines.Count;
+
+ currentStep := 0;
+ currentPlots := TPoints.Create;
+ currentPlots.Add(FindStart);
+ Inc(FPart1);
+ nextPlots := TPoints.Create;
+
+ while currentStep < FMaxSteps do
+ begin
+ for plot in currentPlots do
+ for direction in CDirections do
+ begin
+ next := plot + direction;
+ if IsInBounds(next) and (GetPosition(next) = CPlotChar) then
+ begin
+ SetPosition(next, CTraversedChar);
+ nextPlots.Add(next);
+ end;
+ end;
+
+ currentPlots.Clear;
+ temp := currentPlots;
+ currentPlots := nextPlots;
+ nextPlots := temp;
+ Inc(currentStep);
+
+ // Positions where the number of steps are even can be reached with trivial backtracking, so they count.
+ if currentStep mod 2 = 0 then
+ //begin
+ Inc(FPart1, currentPlots.Count);
+ // for plot in currentPlots do
+ // SetPosition(plot, 'O');
+ //end;
+
+ //for s in FLines do
+ // WriteLn(s);
+ //WriteLn;
+ end;
+
+ currentPlots.Free;
+ nextPlots.Free;
+end;
+
+function TStepCounter.GetDataFileName: string;
+begin
+ Result := 'step_counter.txt';
+end;
+
+function TStepCounter.GetPuzzleName: string;
+begin
+ Result := 'Day 21: Step Counter';
+end;
+
+end.
+
diff --git a/tests/AdventOfCodeFPCUnit.lpi b/tests/AdventOfCodeFPCUnit.lpi
index 6a6220f..64daaed 100644
--- a/tests/AdventOfCodeFPCUnit.lpi
+++ b/tests/AdventOfCodeFPCUnit.lpi
@@ -124,6 +124,10 @@
+
+
+
+
diff --git a/tests/AdventOfCodeFPCUnit.lpr b/tests/AdventOfCodeFPCUnit.lpr
index 58d65a8..f7c9310 100644
--- a/tests/AdventOfCodeFPCUnit.lpr
+++ b/tests/AdventOfCodeFPCUnit.lpr
@@ -8,7 +8,7 @@ uses
UHauntedWastelandTestCases, UMirageMaintenanceTestCases, UPipeMazeTestCases, UCosmicExpansionTestCases,
UHotSpringsTestCases, UPointOfIncidenceTestCases, UParabolicReflectorDishTestCases, ULensLibraryTestCases,
UFloorWillBeLavaTestCases, UClumsyCrucibleTestCases, ULavaductLagoonTestCases, UAplentyTestCases,
-UPulsePropagationTestCases;
+ UPulsePropagationTestCases, UStepCounterTestCases;
{$R *.res}
diff --git a/tests/UStepCounterTestCases.pas b/tests/UStepCounterTestCases.pas
new file mode 100644
index 0000000..802b7ad
--- /dev/null
+++ b/tests/UStepCounterTestCases.pas
@@ -0,0 +1,82 @@
+{
+ 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 UStepCounterTestCases;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, fpcunit, testregistry, USolver, UBaseTestCases, UStepCounter;
+
+type
+
+ { TStepCounterFullDataTestCase }
+
+ TStepCounterFullDataTestCase = class(TEngineBaseTest)
+ protected
+ function CreateSolver: ISolver; override;
+ published
+ procedure TestPart1;
+ end;
+
+ { TStepCounterMax6ExampleTestCase }
+
+ TStepCounterMax6ExampleTestCase = class(TExampleEngineBaseTest)
+ protected
+ function CreateSolver: ISolver; override;
+ published
+ procedure TestPart1;
+ end;
+
+implementation
+
+{ TStepCounterFullDataTestCase }
+
+function TStepCounterFullDataTestCase.CreateSolver: ISolver;
+begin
+ Result := TStepCounter.Create;
+end;
+
+procedure TStepCounterFullDataTestCase.TestPart1;
+begin
+ AssertEquals(3809, FSolver.GetResultPart1);
+end;
+
+{ TStepCounterMax6ExampleTestCase }
+
+function TStepCounterMax6ExampleTestCase.CreateSolver: ISolver;
+var
+ solver: TStepCounter;
+begin
+ solver := TStepCounter.Create;
+ solver.MaxSteps := 6;
+ Result := solver;
+end;
+
+procedure TStepCounterMax6ExampleTestCase.TestPart1;
+begin
+ AssertEquals(16, FSolver.GetResultPart1);
+end;
+
+initialization
+
+ RegisterTest(TStepCounterFullDataTestCase);
+ RegisterTest(TStepCounterMax6ExampleTestCase);
+end.
+