Added solution for "Day 8: Haunted Wasteland", part 2
This commit is contained in:
parent
edf9cf3d72
commit
f1b1439524
|
@ -22,7 +22,7 @@ unit UHauntedWasteland;
|
|||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Generics.Collections, USolver;
|
||||
Classes, SysUtils, Generics.Collections, USolver, UNumberTheory;
|
||||
|
||||
type
|
||||
|
||||
|
@ -36,7 +36,7 @@ type
|
|||
constructor Create(const AName: string);
|
||||
property Name: string read FName;
|
||||
procedure AddNeighbors(constref ALeft, ARight: TNode);
|
||||
function TryStep(const ADirection: Char; out ONewLocation: TNode): Boolean;
|
||||
function Step(const ADirection: Char): TNode;
|
||||
end;
|
||||
|
||||
TNodes = specialize TObjectList<TNode>;
|
||||
|
@ -47,10 +47,10 @@ type
|
|||
private
|
||||
FDirections: string;
|
||||
FNextDirectionIndex: Integer;
|
||||
FNodes, FUnparsedNodes: TNodes;
|
||||
FCurrentNode, FTargetNode: TNode;
|
||||
FNodes, FUnparsedNodes, FGhostCurrentNodes: TNodes;
|
||||
procedure ProcessNode(const ALine: string);
|
||||
procedure DoSteps;
|
||||
procedure IncDirectionIndex;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
|
@ -77,23 +77,16 @@ begin
|
|||
FRight := ARight;
|
||||
end;
|
||||
|
||||
function TNode.TryStep(const ADirection: Char; out ONewLocation: TNode): Boolean;
|
||||
function TNode.Step(const ADirection: Char): TNode;
|
||||
begin
|
||||
ONewLocation := nil;
|
||||
Result := False;
|
||||
Result := nil;
|
||||
case ADirection of
|
||||
'L':
|
||||
if FLeft <> nil then
|
||||
begin
|
||||
ONewLocation := FLeft;
|
||||
Result := True;
|
||||
end;
|
||||
Result := FLeft;
|
||||
'R':
|
||||
if FRight <> nil then
|
||||
begin
|
||||
ONewLocation := FRight;
|
||||
Result := True;
|
||||
end;
|
||||
Result := FRight;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -169,43 +162,71 @@ begin
|
|||
|
||||
parsingNode.AddNeighbors(leftNode, rightNode);
|
||||
|
||||
// Checks for start and end nodes.
|
||||
if name = 'ZZZ' then
|
||||
FTargetNode := parsingNode
|
||||
else if name = 'AAA' then
|
||||
FCurrentNode := parsingNode;
|
||||
// Checks for start nodes.
|
||||
if name[3] = 'A' then
|
||||
FGhostCurrentNodes.Add(parsingNode);
|
||||
end;
|
||||
|
||||
procedure THauntedWasteland.DoSteps;
|
||||
var
|
||||
new: TNode;
|
||||
counts: specialize TList<Cardinal>;
|
||||
gcd, count: Cardinal;
|
||||
node, current: TNode;
|
||||
begin
|
||||
if FCurrentNode <> nil then
|
||||
gcd := 0;
|
||||
counts := specialize TList<Cardinal>.Create;
|
||||
counts.Capacity := FGhostCurrentNodes.Count;
|
||||
|
||||
for node in FGhostCurrentNodes do
|
||||
begin
|
||||
while (FCurrentNode <> FTargetNode) and FCurrentNode.TryStep(FDirections[FNextDirectionIndex], new) do
|
||||
current := node;
|
||||
FNextDirectionIndex := 1;
|
||||
count := 0;
|
||||
repeat
|
||||
current := current.Step(FDirections[FNextDirectionIndex]);
|
||||
IncDirectionIndex;
|
||||
Inc(count);
|
||||
until current.Name[3] = 'Z';
|
||||
|
||||
if node.Name = 'AAA' then
|
||||
FPart1 := count;
|
||||
|
||||
counts.Add(count);
|
||||
if gcd = 0 then
|
||||
gcd := count;
|
||||
gcd := TNumberTheory.GreatestCommonDivisor(gcd, count);
|
||||
end;
|
||||
|
||||
for count in counts do
|
||||
begin
|
||||
FCurrentNode := new;
|
||||
if FPart2 = 0 then
|
||||
FPart2 := count
|
||||
else
|
||||
FPart2 := count div gcd * FPart2;
|
||||
end;
|
||||
|
||||
counts.Free;
|
||||
end;
|
||||
|
||||
procedure THauntedWasteland.IncDirectionIndex;
|
||||
begin
|
||||
Inc(FNextDirectionIndex);
|
||||
if FNextDirectionIndex > Length(FDirections) then
|
||||
FNextDirectionIndex := 1;
|
||||
Inc(FPart1);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor THauntedWasteland.Create;
|
||||
begin
|
||||
FNextDirectionIndex := 1;
|
||||
FNodes := TNodes.Create;
|
||||
FUnparsedNodes := TNodes.Create(False);
|
||||
FCurrentNode := nil;
|
||||
FTargetNode := nil;
|
||||
FGhostCurrentNodes := TNodes.Create(False);
|
||||
end;
|
||||
|
||||
destructor THauntedWasteland.Destroy;
|
||||
begin
|
||||
FNodes.Free;
|
||||
FUnparsedNodes.Free;
|
||||
FGhostCurrentNodes.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
|
@ -213,16 +234,13 @@ procedure THauntedWasteland.ProcessDataLine(const ALine: string);
|
|||
begin
|
||||
if FDirections = '' then
|
||||
FDirections := ALine
|
||||
else if (ALine <> '') and ((FTargetNode = nil) or (FCurrentNode <> FTargetNode)) then
|
||||
begin
|
||||
else if ALine <> '' then
|
||||
ProcessNode(ALine);
|
||||
DoSteps;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure THauntedWasteland.Finish;
|
||||
begin
|
||||
|
||||
DoSteps;
|
||||
end;
|
||||
|
||||
function THauntedWasteland.GetDataFileName: string;
|
||||
|
|
|
@ -33,6 +33,7 @@ type
|
|||
function CreateSolver: ISolver; override;
|
||||
published
|
||||
procedure TestPart1;
|
||||
procedure TestPart2;
|
||||
end;
|
||||
|
||||
{ THauntedWastelandExampleTestCase }
|
||||
|
@ -59,6 +60,21 @@ type
|
|||
procedure TestPart1;
|
||||
end;
|
||||
|
||||
{ TExample3HauntedWasteland }
|
||||
|
||||
TExample3HauntedWasteland = class(THauntedWasteland)
|
||||
function GetDataFileName: string; override;
|
||||
end;
|
||||
|
||||
{ THauntedWastelandExample3TestCase }
|
||||
|
||||
THauntedWastelandExample3TestCase = class(TExampleEngineBaseTest)
|
||||
protected
|
||||
function CreateSolver: ISolver; override;
|
||||
published
|
||||
procedure TestPart2;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ THauntedWastelandFullDataTestCase }
|
||||
|
@ -73,6 +89,11 @@ begin
|
|||
AssertEquals(14257, FSolver.GetResultPart1);
|
||||
end;
|
||||
|
||||
procedure THauntedWastelandFullDataTestCase.TestPart2;
|
||||
begin
|
||||
AssertEquals(16187743689077, FSolver.GetResultPart2);
|
||||
end;
|
||||
|
||||
{ THauntedWastelandExampleTestCase }
|
||||
|
||||
function THauntedWastelandExampleTestCase.CreateSolver: ISolver;
|
||||
|
@ -104,9 +125,29 @@ begin
|
|||
AssertEquals(6, FSolver.GetResultPart1);
|
||||
end;
|
||||
|
||||
{ TExample3HauntedWasteland }
|
||||
|
||||
function TExample3HauntedWasteland.GetDataFileName: string;
|
||||
begin
|
||||
Result := 'haunted_wasteland3.txt';
|
||||
end;
|
||||
|
||||
{ THauntedWastelandExample3TestCase }
|
||||
|
||||
function THauntedWastelandExample3TestCase.CreateSolver: ISolver;
|
||||
begin
|
||||
Result := TExample3HauntedWasteland.Create;
|
||||
end;
|
||||
|
||||
procedure THauntedWastelandExample3TestCase.TestPart2;
|
||||
begin
|
||||
AssertEquals(6, FSolver.GetResultPart2);
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
RegisterTest(THauntedWastelandFullDataTestCase);
|
||||
RegisterTest(THauntedWastelandExampleTestCase);
|
||||
RegisterTest(THauntedWastelandExample2TestCase);
|
||||
RegisterTest(THauntedWastelandExample3TestCase);
|
||||
end.
|
||||
|
|
Loading…
Reference in New Issue