209 lines
4.9 KiB
Plaintext
209 lines
4.9 KiB
Plaintext
{
|
|
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 UGiveSeedFertilizer;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, fgl, USolver;
|
|
|
|
type
|
|
|
|
{ TAlmanacMapRange }
|
|
|
|
TAlmanacMapRange = class
|
|
private
|
|
FDestinationStart, FSourceStart, FSourceEnd, FDifference1, FDifference2: Cardinal;
|
|
public
|
|
constructor Create(const ADestinationStart, ASourceStart, ALength: Cardinal);
|
|
function TryConvert(const AInput: Cardinal; out OOutput: Cardinal): Boolean;
|
|
end;
|
|
|
|
{ TAlmanacMap }
|
|
|
|
TAlmanacMap = class
|
|
private
|
|
FRanges: specialize TFPGObjectList<TAlmanacMapRange>;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure AddMapRange(const ALine: string);
|
|
function Convert(const AInput: Cardinal): Cardinal;
|
|
end;
|
|
|
|
{ TGiveSeedFertilizer }
|
|
|
|
TGiveSeedFertilizer = class(TSolver)
|
|
private
|
|
FSeeds: specialize TFPGList<Cardinal>;
|
|
FMaps: specialize TFPGObjectList<TAlmanacMap>;
|
|
procedure ProcessSeeds(const ALine: string);
|
|
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
|
|
|
|
{ TAlmanacMapRange }
|
|
|
|
constructor TAlmanacMapRange.Create(const ADestinationStart, ASourceStart, ALength: Cardinal);
|
|
begin
|
|
FDestinationStart := ADestinationStart;
|
|
FSourceStart := ASourceStart;
|
|
|
|
// All input values are within Cardinal range, but the calculations might not be.
|
|
if ASourceStart <= Cardinal.MaxValue - ALength then
|
|
FSourceEnd := ASourceStart + ALength
|
|
else
|
|
FSourceEnd := Cardinal.MaxValue;
|
|
|
|
if ADestinationStart >= ASourceStart then
|
|
begin
|
|
FDifference1 := ADestinationStart - ASourceStart;
|
|
FDifference2 := 0;
|
|
end
|
|
else begin
|
|
FDifference1 := 0;
|
|
FDifference2 := ASourceStart - ADestinationStart;
|
|
end;
|
|
end;
|
|
|
|
function TAlmanacMapRange.TryConvert(const AInput: Cardinal; out OOutput: Cardinal): Boolean;
|
|
begin
|
|
if (FSourceStart <= AInput) and (AInput < FSourceEnd) then
|
|
begin
|
|
if FDifference1 > 0 then
|
|
OOutput := AInput + FDifference1
|
|
else
|
|
OOutput := AInput - FDifference2;
|
|
Result := True;
|
|
end
|
|
else begin
|
|
OOutput := 0;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{ TAlmanacMap }
|
|
|
|
constructor TAlmanacMap.Create;
|
|
begin
|
|
FRanges := specialize TFPGObjectList<TAlmanacMapRange>.Create;
|
|
end;
|
|
|
|
destructor TAlmanacMap.Destroy;
|
|
begin
|
|
FRanges.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TAlmanacMap.AddMapRange(const ALine: string);
|
|
var
|
|
split: TStringArray;
|
|
begin
|
|
split := ALine.Split(' ');
|
|
FRanges.Add(TAlmanacMapRange.Create(StrToDWord(split[0]), StrToDWord(split[1]), StrToDWord(split[2])));
|
|
end;
|
|
|
|
function TAlmanacMap.Convert(const AInput: Cardinal): Cardinal;
|
|
var
|
|
range: TAlmanacMapRange;
|
|
begin
|
|
for range in FRanges do
|
|
begin
|
|
if range.TryConvert(AInput, Result) then
|
|
Exit;
|
|
end;
|
|
|
|
Result := AInput;
|
|
end;
|
|
|
|
{ TGiveSeedFertilizer }
|
|
|
|
procedure TGiveSeedFertilizer.ProcessSeeds(const ALine: string);
|
|
var
|
|
split: TStringArray;
|
|
i: Integer;
|
|
begin
|
|
split := Aline.Split(' ');
|
|
for i := 1 to Length(split) - 1 do
|
|
begin
|
|
FSeeds.Add(StrToDWord(split[i]));
|
|
end;
|
|
end;
|
|
|
|
constructor TGiveSeedFertilizer.Create;
|
|
begin
|
|
FSeeds := specialize TFPGList<Cardinal>.Create;
|
|
FMaps := specialize TFPGObjectList<TAlmanacMap>.Create;
|
|
end;
|
|
|
|
destructor TGiveSeedFertilizer.Destroy;
|
|
begin
|
|
FSeeds.Free;
|
|
FMaps.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TGiveSeedFertilizer.ProcessDataLine(const ALine: string);
|
|
begin
|
|
if LeftStr(ALine, 6) = 'seeds:' then
|
|
ProcessSeeds(ALine)
|
|
else if RightStr(ALine, 4) = 'map:' then
|
|
FMaps.Add(TAlmanacMap.Create)
|
|
else if Aline <> '' then
|
|
FMaps.Last.AddMapRange(ALine);
|
|
end;
|
|
|
|
procedure TGiveSeedFertilizer.Finish;
|
|
var
|
|
seed, value: Cardinal;
|
|
map: TAlmanacMap;
|
|
begin
|
|
for seed in FSeeds do
|
|
begin
|
|
value := seed;
|
|
for map in FMaps do
|
|
begin
|
|
value := map.Convert(value);
|
|
end;
|
|
if (FPart1 = 0) or (value < FPart1) then
|
|
FPart1 := value;
|
|
end;
|
|
end;
|
|
|
|
function TGiveSeedFertilizer.GetDataFileName: string;
|
|
begin
|
|
Result := 'give_seed_fertilizer.txt';
|
|
end;
|
|
|
|
function TGiveSeedFertilizer.GetPuzzleName: string;
|
|
begin
|
|
Result := 'Day 5: If You Give A Seed A Fertilizer';
|
|
end;
|
|
|
|
end.
|
|
|