AdventOfCode2023/solvers/UGearRatios.pas

148 lines
3.9 KiB
Plaintext
Raw Normal View History

{
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 UGearRatios;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, USolver;
const
CDigitChars = ['0'..'9'];
CNonSymbolChars = ['0'..'9', '.'];
type
{ TGearRatios }
TGearRatios = class(TSolver)
private
FPreviousLine, FLine: string;
procedure ProcessDataLineTriplet(const APreviousLine, ALine, ANextLine: string);
public
procedure ProcessDataLine(const ALine: string); override;
procedure Finish; override;
function GetDataFileName: string; override;
function GetPuzzleName: string; override;
end;
implementation
{ TGearRatios }
procedure TGearRatios.ProcessDataLineTriplet(const APreviousLine, ALine, ANextLine: string);
var
i, numberStart, numberLength, partNumber: Integer;
inNumber, isPartNumber: Boolean;
begin
inNumber := False;
for i := 1 to ALine.Length do
begin
// Checks if number starts.
if not inNumber and (ALine[i] in CDigitChars) then
begin
inNumber := True;
numberStart := i;
// Checks for a symbol in the column before the first digit.
isPartNumber := (i > 1) and
(not (APreviousLine[i - 1] in CNonSymbolChars)
or not (ALine[i - 1] in CNonSymbolChars)
or not (ANextLine[i - 1] in CNonSymbolChars));
end;
// Checks for a symbol in the column of the current digit.
if inNumber and not isPartNumber and
(not (APreviousLine[i] in CNonSymbolChars)
or not (ANextLine[i] in CNonSymbolChars)) then
begin
isPartNumber := True;
end;
// Checks if number ends.
if inNumber and (not (ALine[i] in CDigitChars) or (i = ALine.Length)) then
begin
inNumber := False;
// Checks for a symbol in the column after the last digit.
if not (APreviousLine[i] in CNonSymbolChars)
or not (ALine[i] in CNonSymbolChars)
or not (ANextLine[i] in CNonSymbolChars) then
begin
isPartNumber := True;
end;
// Counts if it is a part number.
if isPartNumber then
begin
numberLength := i - numberStart;
if ALine[i] in CDigitChars then
Inc(numberLength);
partNumber := StrToInt(Copy(ALine, numberStart, numberLength));
Inc(FPart1, partNumber);
end;
end;
end;
end;
procedure TGearRatios.ProcessDataLine(const ALine: string);
begin
if not (FLine = '') then
begin
// Processes lines 2 to n - 1 in calls for lines 3 to n.
ProcessDataLineTriplet(FPreviousLine, FLine, ALine);
FPreviousLine := FLine;
FLine := ALine;
end
else if not (FPreviousLine = '') then
begin
// Processes line 1 in call for line 2.
FLine := ALine;
// Duplicates the first line for the algorithm because it does not influence the result.
ProcessDataLineTriplet(FPreviousLine, FPreviousLine, FLine);
end
else
// Processes nothing in call for line 1.
FPreviousLine := ALine;
end;
procedure TGearRatios.Finish;
begin
// Processes line n.
// Duplicates the last line for the algorithm because it does not influence the result.
if FLine = '' then
FLine := FPreviousLine;
ProcessDataLineTriplet(FPreviousLine, FLine, FLine);
end;
function TGearRatios.GetDataFileName: string;
begin
Result := 'gear_ratios.txt';
end;
function TGearRatios.GetPuzzleName: string;
begin
Result := 'Day 3: Gear Ratios';
end;
end.