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"/> <Filename Value="solvers\USnowverload.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit> </Unit>
<Unit>
<Filename Value="UCommon.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <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. 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 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 the terms of the GNU General Public License as published by the Free Software
@ -22,7 +22,7 @@ unit UFloorWillBeLava;
interface interface
uses uses
Classes, SysUtils, Generics.Collections, USolver; Classes, SysUtils, Generics.Collections, USolver, UCommon;
type type
@ -37,7 +37,7 @@ type
{ TTransition } { TTransition }
TTransition = record TTransition = record
IncomingDirection, OutgoingDirection, SplitDirection: TPoint; IncomingDirection, OutgoingDirection, SplitDirection: PPoint;
Tile: Char; Tile: Char;
EnergyChange: TEnergyState; EnergyChange: TEnergyState;
end; end;
@ -73,32 +73,31 @@ type
end; end;
const const
CNoDirection: TPoint = (X: 0; Y: 0);
CEmptyChar = '.'; CEmptyChar = '.';
CTransitions: array of TTransition = ( 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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) EnergyChange: esBoth)
); );
@ -193,11 +192,11 @@ begin
begin begin
// Checks the current position for direction changes and splits. // Checks the current position for direction changes and splits.
for transition in CTransitions do 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 begin
if transition.SplitDirection <> CNoDirection then if transition.SplitDirection^ <> CNoDirection then
stack.Push(GetNewBeam(ABeam.Position + transition.SplitDirection, transition.SplitDirection)); stack.Push(GetNewBeam(ABeam.Position + transition.SplitDirection^, transition.SplitDirection^));
ABeam.Direction := transition.OutgoingDirection; ABeam.Direction := transition.OutgoingDirection^;
energyChange := transition.EnergyChange; energyChange := transition.EnergyChange;
Break; Break;
end; end;

View File

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

View File

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

View File

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