{ 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.