Moved common TPoint direction code into new unit

This commit is contained in:
Stefan Müller 2024-06-10 20:48:07 +02:00
parent 19509c6173
commit 8eb76329c1
6 changed files with 108 additions and 70 deletions

View File

@ -153,6 +153,10 @@
<Filename Value="solvers\USnowverload.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="UCommon.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>

45
UCommon.pas Normal file
View File

@ -0,0 +1,45 @@
{
Solutions to the Advent Of Code.
Copyright (C) 2023-2024 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 UCommon;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils;
type
PPoint = ^TPoint;
const
CNoDirection: TPoint = (X: 0; Y: 0);
CDirectionRight: TPoint = (X: 1; Y: 0);
CDirectionDown: TPoint = (X: 0; Y: 1);
CDirectionLeft: TPoint = (X: -1; Y: 0);
CDirectionUp: TPoint = (X: 0; Y: -1);
CDirectionRightDown: TPoint = (X: 1; Y: 1);
CDirectionRightUp: TPoint = (X: 1; Y: -1);
CDirectionLeftDown: TPoint = (X: -1; Y: 1);
CDirectionLeftUp: TPoint = (X: -1; Y: -1);
CPCardinalDirections: array[0..3] of PPoint = (@CDirectionRight, @CDirectionDown, @CDirectionLeft, @CDirectionUp);
implementation
end.

View File

@ -1,6 +1,6 @@
{
Solutions to the Advent Of Code.
Copyright (C) 2023 Stefan Müller
Copyright (C) 2023-2024 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
@ -22,7 +22,7 @@ unit UFloorWillBeLava;
interface
uses
Classes, SysUtils, Generics.Collections, USolver;
Classes, SysUtils, Generics.Collections, USolver, UCommon;
type
@ -37,7 +37,7 @@ type
{ TTransition }
TTransition = record
IncomingDirection, OutgoingDirection, SplitDirection: TPoint;
IncomingDirection, OutgoingDirection, SplitDirection: PPoint;
Tile: Char;
EnergyChange: TEnergyState;
end;
@ -73,32 +73,31 @@ type
end;
const
CNoDirection: TPoint = (X: 0; Y: 0);
CEmptyChar = '.';
CTransitions: array of TTransition = (
(IncomingDirection: (X: 1; Y: 0); OutgoingDirection: (X: 0; Y: -1); SplitDirection: (X: 0; Y: 0); Tile: '/';
(IncomingDirection: @CDirectionRight; OutgoingDirection: @CDirectionUp; SplitDirection: @CNoDirection; Tile: '/';
EnergyChange: esWestOrHorizontal),
(IncomingDirection: (X: 0; Y: 1); OutgoingDirection: (X: -1; Y: 0); SplitDirection: (X: 0; Y: 0); Tile: '/';
(IncomingDirection: @CDirectionDown; OutgoingDirection: @CDirectionLeft; SplitDirection: @CNoDirection; Tile: '/';
EnergyChange: esWestOrHorizontal),
(IncomingDirection: (X: -1; Y: 0); OutgoingDirection: (X: 0; Y: 1); SplitDirection: (X: 0; Y: 0); Tile: '/';
(IncomingDirection: @CDirectionLeft; OutgoingDirection: @CDirectionDown; SplitDirection: @CNoDirection; Tile: '/';
EnergyChange: esEastOrVertical),
(IncomingDirection: (X: 0; Y: -1); OutgoingDirection: (X: 1; Y: 0); SplitDirection: (X: 0; Y: 0); Tile: '/';
(IncomingDirection: @CDirectionUp; OutgoingDirection: @CDirectionRight; SplitDirection: @CNoDirection; Tile: '/';
EnergyChange: esEastOrVertical),
(IncomingDirection: (X: 1; Y: 0); OutgoingDirection: (X: 0; Y: 1); SplitDirection: (X: 0; Y: 0); Tile: '\';
(IncomingDirection: @CDirectionRight; OutgoingDirection: @CDirectionDown; SplitDirection: @CNoDirection; Tile: '\';
EnergyChange: esWestOrHorizontal),
(IncomingDirection: (X: 0; Y: 1); OutgoingDirection: (X: 1; Y: 0); SplitDirection: (X: 0; Y: 0); Tile: '\';
(IncomingDirection: @CDirectionDown; OutgoingDirection: @CDirectionRight; SplitDirection: @CNoDirection; Tile: '\';
EnergyChange: esEastOrVertical),
(IncomingDirection: (X: -1; Y: 0); OutgoingDirection: (X: 0; Y: -1); SplitDirection: (X: 0; Y: 0); Tile: '\';
(IncomingDirection: @CDirectionLeft; OutgoingDirection: @CDirectionUp; SplitDirection: @CNoDirection; Tile: '\';
EnergyChange: esEastOrVertical),
(IncomingDirection: (X: 0; Y: -1); OutgoingDirection: (X: -1; Y: 0); SplitDirection: (X: 0; Y: 0); Tile: '\';
(IncomingDirection: @CDirectionUp; OutgoingDirection: @CDirectionLeft; SplitDirection: @CNoDirection; Tile: '\';
EnergyChange: esWestOrHorizontal),
(IncomingDirection: (X: 1; Y: 0); OutgoingDirection: (X: 0; Y: -1); SplitDirection: (X: 0; Y: 1); Tile: '|';
(IncomingDirection: @CDirectionRight; OutgoingDirection: @CDirectionUp; SplitDirection: @CDirectionDown; Tile: '|';
EnergyChange: esBoth),
(IncomingDirection: (X: -1; Y: 0); OutgoingDirection: (X: 0; Y: -1); SplitDirection: (X: 0; Y: 1); Tile: '|';
(IncomingDirection: @CDirectionLeft; OutgoingDirection: @CDirectionUp; SplitDirection: @CDirectionDown; Tile: '|';
EnergyChange: esBoth),
(IncomingDirection: (X: 0; Y: 1); OutgoingDirection: (X: -1; Y: 0); SplitDirection: (X: 1; Y: 0); Tile: '-';
(IncomingDirection: @CDirectionDown; OutgoingDirection: @CDirectionLeft; SplitDirection: @CDirectionRight; Tile: '-';
EnergyChange: esBoth),
(IncomingDirection: (X: 0; Y: -1); OutgoingDirection: (X: -1; Y: 0); SplitDirection: (X: 1; Y: 0); Tile: '-';
(IncomingDirection: @CDirectionUp; OutgoingDirection: @CDirectionLeft; SplitDirection: @CDirectionRight; Tile: '-';
EnergyChange: esBoth)
);
@ -193,11 +192,11 @@ begin
begin
// Checks the current position for direction changes and splits.
for transition in CTransitions do
if (transition.IncomingDirection = ABeam.Direction) and (transition.Tile = GetTile(ABeam.Position)) then
if (transition.IncomingDirection^ = ABeam.Direction) and (transition.Tile = GetTile(ABeam.Position)) then
begin
if transition.SplitDirection <> CNoDirection then
stack.Push(GetNewBeam(ABeam.Position + transition.SplitDirection, transition.SplitDirection));
ABeam.Direction := transition.OutgoingDirection;
if transition.SplitDirection^ <> CNoDirection then
stack.Push(GetNewBeam(ABeam.Position + transition.SplitDirection^, transition.SplitDirection^));
ABeam.Direction := transition.OutgoingDirection^;
energyChange := transition.EnergyChange;
Break;
end;

View File

@ -1,6 +1,6 @@
{
Solutions to the Advent Of Code.
Copyright (C) 2023 Stefan Müller
Copyright (C) 2023-2024 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
@ -22,7 +22,7 @@ unit ULongWalk;
interface
uses
Classes, SysUtils, Generics.Collections, USolver;
Classes, SysUtils, Generics.Collections, USolver, UCommon;
type
TPoints = specialize TList<TPoint>;
@ -93,15 +93,11 @@ type
function GetPuzzleName: string; override;
end;
TDirection = (dirRight, dirDown, dirLeft, dirUp);
const
CPathChar = '.';
CForestChar = '#';
CRightSlopeChar = '>';
CDownSlopeChar = 'v';
CDirections: array[TDirection] of TPoint = ((X: 1; Y: 0), (X: 0; Y: 1), (X: -1; Y: 0), (X: 0; Y: -1));
CStartReverseDirection: TPoint = (X: 0; Y: -1);
implementation
@ -148,7 +144,7 @@ begin
stack := TPathStartQueue.Create;
pathStart.Position := FStart.Position;
pathStart.Crossing := FStart;
pathStart.ReverseDirection := CStartReverseDirection;
pathStart.ReverseDirection := CDirectionUp;
stack.Enqueue(pathStart);
while stack.Count > 0 do
StepPath(stack);
@ -158,7 +154,8 @@ end;
procedure TLongWalk.StepPath(const AStartPositionQueue: TPathStartQueue);
var
start: TPathStart;
new, direction: TPoint;
new: TPoint;
pdirection: PPoint;
c: Char;
len: Integer;
oneMore, stop: Boolean;
@ -172,14 +169,14 @@ begin
oneMore := False;
stop := False;
repeat
for direction in CDirections do
if direction <> start.ReverseDirection then
for pdirection in CPCardinalDirections do
if pdirection^ <> start.ReverseDirection then
begin
new := start.Position + direction;
new := start.Position + pdirection^;
c := GetPosition(new);
if c <> CForestChar then
begin
start.ReverseDirection := Point(-direction.X, -direction.Y);
start.ReverseDirection := Point(-pdirection^.X, -pdirection^.Y);
start.Position := new;
if oneMore or (new.Y = FLines.Count - 1) then
@ -233,8 +230,8 @@ begin
Result := TCrossing.Create(APosition);
// Checks if the new crossing has multiple entries.
if (GetPosition(APosition + CDirections[dirLeft]) = CRightSlopeChar)
and (GetPosition(APosition + CDirections[dirUp]) = CDownSlopeChar) then
if (GetPosition(APosition + CDirectionLeft) = CRightSlopeChar)
and (GetPosition(APosition + CDirectionUp) = CDownSlopeChar) then
FWaitingForOtherInPath.Add(Result)
else
FCrossings.Add(Result);
@ -244,17 +241,17 @@ begin
// Adds the exits of this crossing to the stack as starts for new paths.
pathStart.Crossing := Result;
pathStart.Position := APosition + CDirections[dirRight];
pathStart.Position := APosition + CDirectionRight;
if GetPosition(pathStart.Position) = CRightSlopeChar then
begin
pathStart.ReverseDirection := CDirections[dirLeft];
pathStart.ReverseDirection := CDirectionLeft;
AStartPositionQueue.Enqueue(pathStart);
end;
pathStart.Position := APosition + CDirections[dirDown];
pathStart.Position := APosition + CDirectionDown;
if GetPosition(pathStart.Position) = CDownSlopeChar then
begin
pathStart.ReverseDirection := CDirections[dirUp];
pathStart.ReverseDirection := CDirectionUp;
AStartPositionQueue.Enqueue(pathStart);
end;
end

View File

@ -1,6 +1,6 @@
{
Solutions to the Advent Of Code.
Copyright (C) 2023 Stefan Müller
Copyright (C) 2023-2024 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
@ -22,7 +22,7 @@ unit UPipeMaze;
interface
uses
Classes, SysUtils, Generics.Collections, USolver;
Classes, SysUtils, Generics.Collections, USolver, UCommon;
const
CStartChar = 'S';
@ -115,24 +115,18 @@ procedure TPipeMaze.InitStepMappings;
var
i: Integer;
begin
FStepMappings.Add(TStepMapping.Create(Point(0, 1), Point(0, 1), '|',
TPointArray.Create(Point(1, 0)),
TPointArray.Create(Point(-1, 0))));
FStepMappings.Add(TStepMapping.Create(Point(1, 0), Point(1, 0), '-',
TPointArray.Create(Point(0, -1)),
TPointArray.Create(Point(0, 1))));
FStepMappings.Add(TStepMapping.Create(Point(-1, 0), Point(0, -1), 'L',
TPointArray.Create(Point(0, 1), Point(-1, 1), Point(-1, 0)),
[]));
FStepMappings.Add(TStepMapping.Create(Point(0, 1), Point(-1, 0), 'J',
TPointArray.Create(Point(1, 0), Point(1, 1), Point(0, 1)),
[]));
FStepMappings.Add(TStepMapping.Create(Point(1, 0), Point(0, 1), '7',
TPointArray.Create(Point(0, -1), Point(1, -1), Point(1, 0)),
[]));
FStepMappings.Add(TStepMapping.Create(Point(0, -1), Point(1, 0), 'F',
TPointArray.Create(Point(-1, 0), Point(-1, -1), Point(0, -1)),
[]));
FStepMappings.Add(TStepMapping.Create(CDirectionDown, CDirectionDown, '|',
TPointArray.Create(CDirectionRight), TPointArray.Create(CDirectionLeft)));
FStepMappings.Add(TStepMapping.Create(CDirectionRight, CDirectionRight, '-',
TPointArray.Create(CDirectionUp), TPointArray.Create(CDirectionDown)));
FStepMappings.Add(TStepMapping.Create(CDirectionLeft, CDirectionUp, 'L',
TPointArray.Create(CDirectionDown, CDirectionLeftDown, CDirectionLeft), []));
FStepMappings.Add(TStepMapping.Create(CDirectionDown, CDirectionLeft, 'J',
TPointArray.Create(CDirectionRight, CDirectionRightDown, CDirectionDown), []));
FStepMappings.Add(TStepMapping.Create(CDirectionRight, CDirectionDown, '7',
TPointArray.Create(CDirectionUp, CDirectionRightUp, CDirectionRight), []));
FStepMappings.Add(TStepMapping.Create(CDirectionUp, CDirectionRight, 'F',
TPointArray.Create(CDirectionLeft, CDirectionLeftUp, CDirectionUp), []));
// Adds reverse step mappings.
for i := 0 to FStepMappings.Count - 1 do
@ -231,13 +225,12 @@ end;
function TPipeMaze.TryCountEnclosureSide(const AChar: Char; out OCount: Int64): Boolean;
var
directions: TPointArray;
stack: specialize TStack<TPoint>;
i, j: Integer;
position, direction, neighbor: TPoint;
position, neighbor: TPoint;
pdirection: PPoint;
c: Char;
begin
directions := TPointArray.Create(Point(0, -1), Point(-1, 0), Point(0, 1), Point(1, 0));
stack := specialize TStack<TPoint>.Create;
OCount := 0;
@ -259,12 +252,12 @@ begin
begin
position := stack.Pop;
for direction in directions do
for pdirection in CPCardinalDirections do
begin
if CheckMapBounds(position + direction) then
if CheckMapBounds(position + pdirection^) then
begin
// Checks the neighboring position.
neighbor := position + direction;
neighbor := position + pdirection^;
c := GetEnclosureMapChar(neighbor);
if (c <> CFloodFillChar) and (c <> CPathChar) then
begin

View File

@ -1,6 +1,6 @@
{
Solutions to the Advent Of Code.
Copyright (C) 2023 Stefan Müller
Copyright (C) 2023-2024 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
@ -22,7 +22,7 @@ unit UStepCounter;
interface
uses
Classes, SysUtils, Generics.Collections, USolver;
Classes, SysUtils, Generics.Collections, USolver, UCommon;
type
TPoints = specialize TList<TPoint>;
@ -50,7 +50,6 @@ const
CStartChar = 'S';
CPlotChar = '.';
CTraversedChar = '+';
CDirections: array of TPoint = ((X: 1; Y: 0), (X: -1; Y: 0), (X: 0; Y: 1), (X: 0; Y: -1));
implementation
@ -110,7 +109,8 @@ procedure TStepCounter.Finish;
var
currentStep: Integer;
currentPlots, nextPlots, temp: TPoints;
plot, direction, next: TPoint;
plot, next: TPoint;
pdirection: PPoint;
begin
FWidth := Length(FLines[0]);
FHeight := FLines.Count;
@ -124,9 +124,9 @@ begin
while currentStep < FMaxSteps do
begin
for plot in currentPlots do
for direction in CDirections do
for pdirection in CPCardinalDirections do
begin
next := plot + direction;
next := plot + pdirection^;
if IsInBounds(next) and (GetPosition(next) = CPlotChar) then
begin
SetPosition(next, CTraversedChar);