Added solution for "Day 21: Step Counter", part 1

This commit is contained in:
Stefan Müller 2023-12-21 21:11:31 +01:00 committed by Stefan Müller
parent 8d5757fae0
commit bc2568756b
6 changed files with 266 additions and 2 deletions

View File

@ -121,6 +121,10 @@
<Filename Value="solvers\UPulsePropagation.pas"/> <Filename Value="solvers\UPulsePropagation.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit> </Unit>
<Unit>
<Filename Value="solvers\UStepCounter.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -27,7 +27,7 @@ uses
UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer, UWaitForIt, UCamelCards, UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer, UWaitForIt, UCamelCards,
UHauntedWasteland, UNumberTheory, UMirageMaintenance, UPipeMaze, UCosmicExpansion, UHotSprings, UPointOfIncidence, UHauntedWasteland, UNumberTheory, UMirageMaintenance, UPipeMaze, UCosmicExpansion, UHotSprings, UPointOfIncidence,
UParabolicReflectorDish, ULensLibrary, UFloorWillBeLava, UClumsyCrucible, ULavaductLagoon, UAplenty, UParabolicReflectorDish, ULensLibrary, UFloorWillBeLava, UClumsyCrucible, ULavaductLagoon, UAplenty,
UPulsePropagation; UPulsePropagation, UStepCounter;
type type
@ -89,6 +89,7 @@ begin
18: engine.RunAndFree(TLavaductLagoon.Create); 18: engine.RunAndFree(TLavaductLagoon.Create);
19: engine.RunAndFree(TAplenty.Create); 19: engine.RunAndFree(TAplenty.Create);
20: engine.RunAndFree(TPulsePropagation.Create); 20: engine.RunAndFree(TPulsePropagation.Create);
21: engine.RunAndFree(TStepCounter.Create);
end; end;
engine.Free; engine.Free;

173
solvers/UStepCounter.pas Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
}
unit UStepCounter;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, Generics.Collections, USolver;
type
TPoints = specialize TList<TPoint>;
{ 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.

View File

@ -124,6 +124,10 @@
<Filename Value="UPulsePropagationTestCases.pas"/> <Filename Value="UPulsePropagationTestCases.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit> </Unit>
<Unit>
<Filename Value="UStepCounterTestCases.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -8,7 +8,7 @@ uses
UHauntedWastelandTestCases, UMirageMaintenanceTestCases, UPipeMazeTestCases, UCosmicExpansionTestCases, UHauntedWastelandTestCases, UMirageMaintenanceTestCases, UPipeMazeTestCases, UCosmicExpansionTestCases,
UHotSpringsTestCases, UPointOfIncidenceTestCases, UParabolicReflectorDishTestCases, ULensLibraryTestCases, UHotSpringsTestCases, UPointOfIncidenceTestCases, UParabolicReflectorDishTestCases, ULensLibraryTestCases,
UFloorWillBeLavaTestCases, UClumsyCrucibleTestCases, ULavaductLagoonTestCases, UAplentyTestCases, UFloorWillBeLavaTestCases, UClumsyCrucibleTestCases, ULavaductLagoonTestCases, UAplentyTestCases,
UPulsePropagationTestCases; UPulsePropagationTestCases, UStepCounterTestCases;
{$R *.res} {$R *.res}

View File

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