Day 9 of Advent of Code has chain of elements following each other on a grid, and as with Advent of Code in Unreal Engine Day 8 I have stuck with using C++ and a TDD-lite approach, within Unreal.
I start with a single test that matches the example from the puzzle description:
// Part 1 Example const TArray< FString > Example = { TEXT("R 4"), TEXT("U 4"), TEXT("L 3"), TEXT("D 1"), TEXT("R 4"), TEXT("D 1"), TEXT("L 5"), TEXT("R 2") }; TestEqual(TEXT("Example Tail Visits 13"), UAoC22BPFunctionLibrary::D09_Calculate(Example), 13);
My solution (not shown) works and Part 2 is reveled to be the same but with a longer chain. I add the new tests cases for Part 2:
// Part 2 Tests TestEqual(TEXT("(Long Rope) Tail Visits 1"), UAoC22BPFunctionLibrary::D09_Calculate(Example, 10), 1); const TArray< FString > LargerExample = { TEXT("R 5"), TEXT("U 8"), TEXT("L 8"), TEXT("D 3"), TEXT("R 17"), TEXT("D 10"), TEXT("L 25"), TEXT("U 20") }; TestEqual(TEXT("Larger Example Visits 36"), UAoC22BPFunctionLibrary::D09_Calculate(LargerExample, 10), 36);
And then generalize the Part 1 answer from hard-coded 2-element chain, to arbitrary length chains:
int UAoC22BPFunctionLibrary::D09_Calculate(const TArray<FString>& Input, int Len) { ensure(Len>0); TArray< FVector2d > Rope; Rope.AddZeroed(Len); TSet< FVector2d > Visited; Visited.Add(Rope.Last()); for (const FString& Command : Input) { FString Left, Right; Command.Split(TEXT(" "), &Left, &Right); FVector2d Dir; if (Left == "U") Dir = {0,1}; else if (Left == "D") Dir = {0,-1}; else if (Left == "L") Dir = {1,0}; else if (Left == "R") Dir = {-1,0}; int Count = FCString::Atoi(*Right); while(Count--) { Rope[0] += Dir; for (int i=1;i!=Rope.Num();++i) { // check for "not touching" const FVector2d TailToHead(Rope[i-1]-Rope[i]); if (TailToHead.SquaredLength()>2) { if (Rope[i].X < Rope[i-1].X) Rope[i].X++; else if (Rope[i].X > Rope[i-1].X) Rope[i].X--; if (Rope[i].Y < Rope[i-1].Y) Rope[i].Y++; else if (Rope[i].Y > Rope[i-1].Y) Rope[i].Y--; } } Visited.Add(Rope.Last()); } } return Visited.Num(); }
It is worth noting that in this code, I am using Unreal’s TSet with a floating-point FVector2d. This is not something I would recommend in production code, and could certainly have put my getting the right answer at risk, due to the problems with floating point equality comparisons, but it worked perfectly, I expect because the only math operations I am doing are ++ and –, and the rope stays within a few hundred units of its origin, and so my vectors are able to store the positions exactly.