namespace AdventOfCodeLibrary._2022.Day_09 { internal class VirtualPoint { internal int X { get; set; } = 0; internal int Y { get; set; } = 0; internal void Translate(int x, int y) { X += x; Y += y; } } internal class RopeWalker { private List TailVistedLocations = new(); internal int ProcessMovement(string[] movements, int ropeLength) { VirtualPoint[] rope = new VirtualPoint[ropeLength]; for (int ropeIndex = 0; ropeIndex < rope.Length; ropeIndex++) { rope[ropeIndex] = new VirtualPoint(); } // add the start position TailVistedLocations.Add($"0,0"); for (int movementIndex = 0; movementIndex < movements.Length; movementIndex++) { char direction = movements[movementIndex][0]; int amountToMove = Convert.ToInt32(movements[movementIndex].Substring(2)); for (int movement = 0; movement < amountToMove; movement++) { // do the actual move switch (direction) { case 'U': rope[0].Translate(0, 1); break; case 'D': rope[0].Translate(0, -1); break; case 'R': rope[0].Translate(1, 0); break; case 'L': rope[0].Translate(-1, 0); break; } for (int ropeIndex = 1; ropeIndex < rope.Length; ropeIndex++) { if (!IsTailTouchingHead(rope[ropeIndex - 1], rope[ropeIndex])) { rope[ropeIndex].Translate(Math.Sign(rope[ropeIndex - 1].X - rope[ropeIndex].X), Math.Sign(rope[ropeIndex - 1].Y - rope[ropeIndex].Y)); // add the new position to the list of visited positions continue; } // if not touching nothing has changed so stop with checking break; } TailVistedLocations.Add($"{rope[^1].X},{rope[^1].Y}"); } } return TailVistedLocations.Distinct().Count(); } private bool IsTailTouchingHead(VirtualPoint point1, VirtualPoint point2) { return !(Math.Abs(point1.X - point2.X) > 1) && !(Math.Abs(point1.Y - point2.Y) > 1); } } }