{ 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 UScratchcards; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils, Generics.Collections, USolver; type { TScratchcards } TScratchcards = class(TSolver) private FCardCopies: specialize TList; function GetNumber(const AString: string; const AIndex: Integer): Integer; 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 { TScratchcards } function TScratchcards.GetNumber(const AString: string; const AIndex: Integer): Integer; begin Result := StrToInt(Trim(Copy(AString, AIndex * 3 + 1, 3))) end; constructor TScratchcards.Create; begin FCardCopies := specialize TList.Create; end; destructor TScratchcards.Destroy; begin FCardCopies.Free; inherited Destroy; end; procedure TScratchcards.ProcessDataLine(const ALine: string); var cardSplit: TStringArray; wins: array of Integer; count, i, have, win, cardPoints, cardMatches, cardCopies: Integer; begin // Counts copies of this card. if FCardCopies.Count > 0 then begin cardCopies := FCardCopies[0]; FCardCopies.Delete(0); end else cardCopies := 1; Inc(FPart2, cardCopies); cardSplit := ALine.Split([':', '|']); // Determines winning numbers. count := cardSplit[1].Length div 3; SetLength(wins, count); for i := 0 to count - 1 do begin wins[i] := GetNumber(cardSplit[1], i); end; // Checks have numbers against winning numbers. cardPoints := 0; cardMatches := 0; count := cardSplit[2].Length div 3; for i := 0 to count - 1 do begin have := GetNumber(cardSplit[2], i); for win in wins do begin if win = have then begin if cardPoints = 0 then cardPoints := 1 else Inc(cardPoints, cardPoints); Inc(cardMatches); Break; end; end; end; Inc(FPart1, cardPoints); // Adds copies of following cards and deletes the current card count. if FCardCopies.Capacity < cardMatches then FCardCopies.Capacity := cardMatches; for i := 0 to cardMatches - 1 do begin if FCardCopies.Count <= i then FCardCopies.Add(cardCopies + 1) else FCardCopies[i] := FCardCopies[i] + cardCopies; end; end; procedure TScratchcards.Finish; begin end; function TScratchcards.GetDataFileName: string; begin Result := 'scratchcards.txt'; end; function TScratchcards.GetPuzzleName: string; begin Result := 'Day 4: Scratchcards'; end; end.