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