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.
