From f9583e684dd69c296fbbcd25e69b024b8f4d2db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Thu, 14 Dec 2023 17:51:12 +0100 Subject: [PATCH] Added solution for "Day 14: Parabolic Reflector Dish", part 1 --- AdventOfCode.lpi | 4 + AdventOfCode.lpr | 8 +- solvers/UParabolicReflectorDish.pas | 161 +++++++++++++++++++++ tests/AdventOfCodeFPCUnit.lpi | 4 + tests/AdventOfCodeFPCUnit.lpr | 2 +- tests/UParabolicReflectorDishTestCases.pas | 78 ++++++++++ 6 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 solvers/UParabolicReflectorDish.pas create mode 100644 tests/UParabolicReflectorDishTestCases.pas diff --git a/AdventOfCode.lpi b/AdventOfCode.lpi index f3c814a..606b61b 100644 --- a/AdventOfCode.lpi +++ b/AdventOfCode.lpi @@ -89,6 +89,10 @@ + + + + diff --git a/AdventOfCode.lpr b/AdventOfCode.lpr index b355b57..338ddf6 100644 --- a/AdventOfCode.lpr +++ b/AdventOfCode.lpr @@ -23,10 +23,9 @@ uses {$IFDEF UNIX} cthreads, {$ENDIF} - Classes, SysUtils, CustApp, - USolver, - UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer, UWaitForIt, UCamelCards, - UHauntedWasteland, UNumberTheory, UMirageMaintenance, UPipeMaze, UCosmicExpansion, UHotSprings, UPointOfIncidence; + Classes, SysUtils, CustApp, USolver, UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer, + UWaitForIt, UCamelCards, UHauntedWasteland, UNumberTheory, UMirageMaintenance, UPipeMaze, UCosmicExpansion, + UHotSprings, UPointOfIncidence, UParabolicReflectorDish; type @@ -64,6 +63,7 @@ begin engine.RunAndFree(TCosmicExpansion.Create); engine.RunAndFree(THotSprings.Create); engine.RunAndFree(TPointOfIncidence.Create); + engine.RunAndFree(TParabolicReflectorDish.Create); engine.Free; end; diff --git a/solvers/UParabolicReflectorDish.pas b/solvers/UParabolicReflectorDish.pas new file mode 100644 index 0000000..c2d7732 --- /dev/null +++ b/solvers/UParabolicReflectorDish.pas @@ -0,0 +1,161 @@ +{ + 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 UParabolicReflectorDish; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, Generics.Collections, USolver; + +const + CRoundRockChar = 'O'; + CCubeRockChar = '#'; + +type + + { TRockPile } + + TRockPile = class + private + FStart, FLength: Integer; + public + constructor Create(const AStart: Integer); + procedure AddRock; + function Any: Boolean; + procedure SetStart(const AStart: Integer); + function CalcWeight(const ALineCount: Integer): Integer; + end; + + TRockPiles = specialize TObjectList; + + { TParabolicReflectorDish } + + TParabolicReflectorDish = class(TSolver) + private + FLineIndex: Integer; + FActivePiles, FFinishedPiles: TRockPiles; + 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 + +{ TRockPile } + +constructor TRockPile.Create(const AStart: Integer); +begin + FStart := AStart; + FLength := 0; +end; + +procedure TRockPile.AddRock; +begin + Inc(FLength); +end; + +function TRockPile.Any: Boolean; +begin + Result := (FLength > 0); +end; + +procedure TRockPile.SetStart(const AStart: Integer); +begin + FStart := AStart; +end; + +function TRockPile.CalcWeight(const ALineCount: Integer): Integer; +begin + Result := (2 * (ALineCount - FStart) - FLength + 1) * FLength div 2; +end; + +{ TParabolicReflectorDish } + +constructor TParabolicReflectorDish.Create; +begin + FLineIndex := 0; + FActivePiles := TRockPiles.Create; + FFinishedPiles := TRockPiles.Create; +end; + +destructor TParabolicReflectorDish.Destroy; +begin + FActivePiles.Free; + FFinishedPiles.Free; + inherited Destroy; +end; + +procedure TParabolicReflectorDish.ProcessDataLine(const ALine: string); +var + i: Integer; +begin + Inc(FLineIndex); + + // Initializes the list of active piles, one per column. + if FActivePiles.Count = 0 then + begin + FActivePiles.Count := Length(ALine); + for i:= 0 to FActivePiles.Count - 1 do + FActivePiles[i] := TRockPile.Create(0); + end; + + // Updates the active piles from the current line. + for i := 1 to Length(ALine) do + begin + case ALine[i] of + CRoundRockChar: FActivePiles[i - 1].AddRock; + CCubeRockChar: + if FActivePiles[i - 1].Any then + begin + FFinishedPiles.Add(FActivePiles.ExtractIndex(i - 1)); + FActivePiles.Insert(i - 1, TRockPile.Create(FLineIndex)); + end + else + FActivePiles[i - 1].SetStart(FLineIndex); + end; + end; +end; + +procedure TParabolicReflectorDish.Finish; +var + i: Integer; +begin + for i := 0 to FFinishedPiles.Count - 1 do + Inc(FPart1, FFinishedPiles[i].CalcWeight(FLineIndex)); + for i := 0 to FActivePiles.Count - 1 do + Inc(FPart1, FActivePiles[i].CalcWeight(FLineIndex)); +end; + +function TParabolicReflectorDish.GetDataFileName: string; +begin + Result := 'parabolic_reflector_dish.txt'; +end; + +function TParabolicReflectorDish.GetPuzzleName: string; +begin + Result := 'Day 14: Parabolic Reflector Dish'; +end; + +end. + diff --git a/tests/AdventOfCodeFPCUnit.lpi b/tests/AdventOfCodeFPCUnit.lpi index 9282724..bc6bfbd 100644 --- a/tests/AdventOfCodeFPCUnit.lpi +++ b/tests/AdventOfCodeFPCUnit.lpi @@ -96,6 +96,10 @@ + + + + diff --git a/tests/AdventOfCodeFPCUnit.lpr b/tests/AdventOfCodeFPCUnit.lpr index ecd15fb..08a515b 100644 --- a/tests/AdventOfCodeFPCUnit.lpr +++ b/tests/AdventOfCodeFPCUnit.lpr @@ -6,7 +6,7 @@ uses Interfaces, Forms, GuiTestRunner, USolver, UBaseTestCases, UTrebuchetTestCases, UCubeConundrumTestCases, UGearRatiosTestCases, UScratchcardsTestCases, UGiveSeedFertilizerTestCases, UWaitForItTestCases, UCamelCardsTestCases, UHauntedWastelandTestCases, UMirageMaintenanceTestCases, UPipeMazeTestCases, UCosmicExpansionTestCases, - UHotSpringsTestCases, UPointOfIncidenceTestCases; + UHotSpringsTestCases, UPointOfIncidenceTestCases, UParabolicReflectorDishTestCases; {$R *.res} diff --git a/tests/UParabolicReflectorDishTestCases.pas b/tests/UParabolicReflectorDishTestCases.pas new file mode 100644 index 0000000..2d011ac --- /dev/null +++ b/tests/UParabolicReflectorDishTestCases.pas @@ -0,0 +1,78 @@ +{ + 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 UParabolicReflectorDishTestCases; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, fpcunit, testregistry, USolver, UBaseTestCases, UParabolicReflectorDish; + +type + + { TParabolicReflectorDishFullDataTestCase } + + TParabolicReflectorDishFullDataTestCase = class(TEngineBaseTest) + protected + function CreateSolver: ISolver; override; + published + procedure TestPart1; + end; + + { TParabolicReflectorDishExampleTestCase } + + TParabolicReflectorDishExampleTestCase = class(TExampleEngineBaseTest) + protected + function CreateSolver: ISolver; override; + published + procedure TestPart1; + end; + +implementation + +{ TParabolicReflectorDishFullDataTestCase } + +function TParabolicReflectorDishFullDataTestCase.CreateSolver: ISolver; +begin + Result := TParabolicReflectorDish.Create; +end; + +procedure TParabolicReflectorDishFullDataTestCase.TestPart1; +begin + AssertEquals(-1, FSolver.GetResultPart1); +end; + +{ TParabolicReflectorDishExampleTestCase } + +function TParabolicReflectorDishExampleTestCase.CreateSolver: ISolver; +begin + Result := TParabolicReflectorDish.Create; +end; + +procedure TParabolicReflectorDishExampleTestCase.TestPart1; +begin + AssertEquals(136, FSolver.GetResultPart1); +end; + +initialization + + RegisterTest(TParabolicReflectorDishFullDataTestCase); + RegisterTest(TParabolicReflectorDishExampleTestCase); +end. +