diff --git a/AdventOfCode.lpi b/AdventOfCode.lpi index 2af3826..2a9af4b 100644 --- a/AdventOfCode.lpi +++ b/AdventOfCode.lpi @@ -153,6 +153,10 @@ + + + + diff --git a/UCommon.pas b/UCommon.pas new file mode 100644 index 0000000..0e674d9 --- /dev/null +++ b/UCommon.pas @@ -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 . +} + +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. + diff --git a/solvers/UFloorWillBeLava.pas b/solvers/UFloorWillBeLava.pas index 467b0a2..2c8033b 100644 --- a/solvers/UFloorWillBeLava.pas +++ b/solvers/UFloorWillBeLava.pas @@ -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; diff --git a/solvers/ULongWalk.pas b/solvers/ULongWalk.pas index a57c2e6..4af7fb5 100644 --- a/solvers/ULongWalk.pas +++ b/solvers/ULongWalk.pas @@ -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; @@ -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 diff --git a/solvers/UPipeMaze.pas b/solvers/UPipeMaze.pas index 1f59dd6..8c8d2e3 100644 --- a/solvers/UPipeMaze.pas +++ b/solvers/UPipeMaze.pas @@ -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; 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.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 diff --git a/solvers/UStepCounter.pas b/solvers/UStepCounter.pas index 887cdb7..6227d12 100644 --- a/solvers/UStepCounter.pas +++ b/solvers/UStepCounter.pas @@ -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; @@ -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);