Day 09: Rope Bridge
**
Tracking the tail of a rope as the head moves around based on some rules. Part I is a very short rope. Part II is a longer rope.
Journal
Part I went pretty quickly. There's not a whole lot of code to implement the given rules. Basically, the head moves up, down, left, or right and you figure out where the tail moves.
It seemed like Part II was basically just extending the same thing to a longer rope. So, same stuff but chain the movements together treating each section as a head and tail. And it almost was. There's just an extra case to handle (they hint this in the description) and it took me a bit to figure out what that was.
The extra case is that now a "head" section may have moved diagonally.
The code here is the generalized version that works for Part I and Part II
Relevant Code
type Knot = [number, number];const X = 0;const Y = 1;const getNewPosition = (head: Knot, tail: Knot) => {const position: Knot = [...tail];// head moved left or right of the tail in the same column far enough to move that wayif (Math.abs(head[X] - tail[X]) > 1 && head[Y] === tail[Y]) {position[X] = head[X] - tail[X] > 0 ? head[X] - 1 : head[X] + 1;// head moved up or down in the same row} else if (Math.abs(head[Y] - tail[Y]) > 1 && head[X] === tail[X]) {position[Y] = head[Y] - tail[Y] > 0 ? head[Y] - 1 : head[Y] + 1;// head moved diagonal} else if (Math.abs(head[Y] - tail[Y]) > 1 ||Math.abs(head[X] - tail[X]) > 1) {position[X] = head[X] - tail[X] > 0 ? tail[X] + 1 : tail[X] - 1;position[Y] = head[Y] - tail[Y] > 0 ? tail[Y] + 1 : tail[Y] - 1;}return position;};export const getVisitedCount = (movesStr: string, numKnots: number) => {const moves = movesStr.split("\n").map((move) => move.split(" "));const knots: Knot[] = [];for (let i = 0; i < numKnots; i++) {knots.push([0, 0]);}const visited = new Set(["0,0"]);moves.forEach(([direction, distance]) => {const axis = ["L", "R"].includes(direction) ? X : Y;const value = ["R", "U"].includes(direction) ? 1 : -1;for (let i = 0; i < +distance; i++) {// move the headknots[0][axis] += value;// move the rest of the ropefor (let j = 1; j < knots.length; j++) {knots[j] = getNewPosition(knots[j - 1], knots[j]);}visited.add(knots[knots.length - 1].join(","));}});return visited.size;};
Output
Test Rope
- Part I: 13 positions visited (0 ms)
- Part II: 36 positions visited (0 ms) (this uses a different test input that I didn't bother to include below)
Real Rope
- Part I: 6269 positions visited (18 ms)
- Part II: 2557 positions visited (12 ms)