Added solution for "Day 13: Point of Incidence", part 1

This commit is contained in:
Stefan Müller 2023-12-13 18:38:28 +01:00 committed by Stefan Müller
parent d32297782c
commit 6b888a3f68
6 changed files with 275 additions and 2 deletions

View File

@ -85,6 +85,10 @@
<Filename Value="solvers\UHotSprings.pas"/> <Filename Value="solvers\UHotSprings.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit> </Unit>
<Unit>
<Filename Value="solvers\UPointOfIncidence.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -26,7 +26,7 @@ uses
Classes, SysUtils, CustApp, Classes, SysUtils, CustApp,
USolver, USolver,
UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer, UWaitForIt, UCamelCards, UTrebuchet, UCubeConundrum, UGearRatios, UScratchcards, UGiveSeedFertilizer, UWaitForIt, UCamelCards,
UHauntedWasteland, UNumberTheory, UMirageMaintenance, UPipeMaze, UCosmicExpansion, UHotSprings; UHauntedWasteland, UNumberTheory, UMirageMaintenance, UPipeMaze, UCosmicExpansion, UHotSprings, UPointOfIncidence;
type type
@ -63,6 +63,7 @@ begin
engine.RunAndFree(TPipeMaze.Create); engine.RunAndFree(TPipeMaze.Create);
engine.RunAndFree(TCosmicExpansion.Create); engine.RunAndFree(TCosmicExpansion.Create);
engine.RunAndFree(THotSprings.Create); engine.RunAndFree(THotSprings.Create);
engine.RunAndFree(TPointOfIncidence.Create);
engine.Free; engine.Free;
end; end;

View File

@ -0,0 +1,186 @@
{
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 UPointOfIncidence;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, Generics.Collections, Math, USolver;
type
{ TPointOfIncidence }
TPointOfIncidence = class(TSolver)
private
FLines: TStringList;
FHorizontalMirrorCandidates, FVerticalMirrorCandidates: specialize TList<Integer>;
procedure ProcessPatternLine(const ALine: string);
procedure VerifyHorizontalCandidates(const ANewLine: string);
procedure CheckForNewHorizontalCandidate(const ANewLine: string);
procedure VerifyVerticalCandidates(const ALine: string);
procedure InitializeNewVerticalCandidates(const AFirstLine: string);
procedure FinishPattern;
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
{ TPointOfIncidence }
procedure TPointOfIncidence.ProcessPatternLine(const ALine: string);
begin
VerifyHorizontalCandidates(ALine);
CheckForNewHorizontalCandidate(ALine);
if FLines.Count > 0 then
VerifyVerticalCandidates(ALine)
else
InitializeNewVerticalCandidates(ALine);
FLines.Add(ALine);
end;
procedure TPointOfIncidence.VerifyHorizontalCandidates(const ANewLine: string);
var
i, mirroredIndex: Integer;
begin
// Checks if the current line fulfills the exisiting horizontal mirror candidates.
i := FHorizontalMirrorCandidates.Count - 1;
while i >= 0 do
begin
// Calculates the index of the line that the current line would be a duplicate of in regards to the i-th candidate.
mirroredIndex := 2 * FHorizontalMirrorCandidates[i] - FLines.Count - 1;
if (mirroredIndex >= 0) and (ANewLine <> FLines[mirroredIndex]) then
FHorizontalMirrorCandidates.Delete(i);
Dec(i);
end;
end;
procedure TPointOfIncidence.CheckForNewHorizontalCandidate(const ANewLine: string);
begin
// Checks for new horizontal mirror candidate between ALine and the previous line.
if (FLines.Count > 0) and (ANewLine = FLines[FLines.Count - 1]) then
FHorizontalMirrorCandidates.Add(FLines.Count);
end;
procedure TPointOfIncidence.VerifyVerticalCandidates(const ALine: string);
var
i, j, len, mirror: Integer;
begin
// Checks if the current line fulfills the exisiting vertical mirror candidates.
len := Length(ALine);
i := FVerticalMirrorCandidates.Count - 1;
while i >= 0 do
begin
mirror := FVerticalMirrorCandidates[i];
for j := 0 to Min(mirror - 1, len - mirror - 1) do
begin
if ALine[mirror - j] <> ALine[mirror + j + 1] then
begin
FVerticalMirrorCandidates.Delete(i);
Break;
end;
end;
Dec(i);
end;
end;
procedure TPointOfIncidence.InitializeNewVerticalCandidates(const AFirstLine: string);
var
i, j, len: Integer;
isMirror: Boolean;
begin
// Checks the line for vertical mirror candidates, i.e. mirrors that work for this line.
len := Length(AFirstLine);
for i := 1 to len - 1 do begin
isMirror := True;
for j := 0 to Min(i - 1, len - i - 1) do
begin
if AFirstLine[i - j] <> AFirstLine[i + j + 1] then
begin
isMirror := False;
Break;
end;
end;
if isMirror then
FVerticalMirrorCandidates.Add(i);
end;
end;
procedure TPointOfIncidence.FinishPattern;
var
i: Integer;
begin
for i := 0 to FHorizontalMirrorCandidates.Count - 1 do
Inc(FPart1, FHorizontalMirrorCandidates[i] * 100);
for i := 0 to FVerticalMirrorCandidates.Count - 1 do
Inc(FPart1, FVerticalMirrorCandidates[i]);
FLines.Clear;
FHorizontalMirrorCandidates.Clear;
FVerticalMirrorCandidates.Clear;
end;
constructor TPointOfIncidence.Create;
begin
FLines := TStringList.Create;
FHorizontalMirrorCandidates := specialize TList<Integer>.Create;
FVerticalMirrorCandidates := specialize TList<Integer>.Create;
end;
destructor TPointOfIncidence.Destroy;
begin
FLines.Free;
FHorizontalMirrorCandidates.Free;
FVerticalMirrorCandidates.Free;
inherited Destroy;
end;
procedure TPointOfIncidence.ProcessDataLine(const ALine: string);
begin
if ALine <> '' then
ProcessPatternLine(ALine)
else
FinishPattern;
end;
procedure TPointOfIncidence.Finish;
begin
FinishPattern;
end;
function TPointOfIncidence.GetDataFileName: string;
begin
Result := 'point_of_incidence.txt';
end;
function TPointOfIncidence.GetPuzzleName: string;
begin
Result := 'Day 13: Point of Incidence';
end;
end.

View File

@ -92,6 +92,10 @@
<Filename Value="UHotSpringsTestCases.pas"/> <Filename Value="UHotSpringsTestCases.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit> </Unit>
<Unit>
<Filename Value="UPointOfIncidenceTestCases.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

View File

@ -6,7 +6,7 @@ uses
Interfaces, Forms, GuiTestRunner, USolver, UBaseTestCases, UTrebuchetTestCases, UCubeConundrumTestCases, Interfaces, Forms, GuiTestRunner, USolver, UBaseTestCases, UTrebuchetTestCases, UCubeConundrumTestCases,
UGearRatiosTestCases, UScratchcardsTestCases, UGiveSeedFertilizerTestCases, UWaitForItTestCases, UCamelCardsTestCases, UGearRatiosTestCases, UScratchcardsTestCases, UGiveSeedFertilizerTestCases, UWaitForItTestCases, UCamelCardsTestCases,
UHauntedWastelandTestCases, UMirageMaintenanceTestCases, UPipeMazeTestCases, UCosmicExpansionTestCases, UHauntedWastelandTestCases, UMirageMaintenanceTestCases, UPipeMazeTestCases, UCosmicExpansionTestCases,
UHotSpringsTestCases; UHotSpringsTestCases, UPointOfIncidenceTestCases;
{$R *.res} {$R *.res}

View File

@ -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 <http://www.gnu.org/licenses/>.
}
unit UPointOfIncidenceTestCases;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, fpcunit, testregistry, USolver, UBaseTestCases, UPointOfIncidence;
type
{ TPointOfIncidenceFullDataTestCase }
TPointOfIncidenceFullDataTestCase = class(TEngineBaseTest)
protected
function CreateSolver: ISolver; override;
published
procedure TestPart1;
end;
{ TPointOfIncidenceExampleTestCase }
TPointOfIncidenceExampleTestCase = class(TExampleEngineBaseTest)
protected
function CreateSolver: ISolver; override;
published
procedure TestPart1;
end;
implementation
{ TPointOfIncidenceFullDataTestCase }
function TPointOfIncidenceFullDataTestCase.CreateSolver: ISolver;
begin
Result := TPointOfIncidence.Create;
end;
procedure TPointOfIncidenceFullDataTestCase.TestPart1;
begin
AssertEquals(37718, FSolver.GetResultPart1);
end;
{ TPointOfIncidenceExampleTestCase }
function TPointOfIncidenceExampleTestCase.CreateSolver: ISolver;
begin
Result := TPointOfIncidence.Create;
end;
procedure TPointOfIncidenceExampleTestCase.TestPart1;
begin
AssertEquals(405, FSolver.GetResultPart1);
end;
initialization
RegisterTest(TPointOfIncidenceFullDataTestCase);
RegisterTest(TPointOfIncidenceExampleTestCase);
end.