diff --git a/2022/README.md b/2022/README.md
index 6f326789f82988261614294e40ced7b793e0dd02..af12d7d392510512ae56cf61aeaf5fd10d5c1824 100644
--- a/2022/README.md
+++ b/2022/README.md
@@ -267,11 +267,11 @@ The subproblems are
 
 ### Part 2
 
-...
+The subproblems are essentially the same as before, substituting "the head" and "tail" with "a knot" and "the next knot"
 
 ### Refactoring
 
-...
+We'll replace the explicit `head` and `tail` with an array of `Position`s.
 
 ## Day 10
 
diff --git a/2022/src/main/java/edu/unl/cse/bohn/year2022/Day9.java b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day9.java
index ecb6ad8474b61b1cb8fad324417c92fdc5774e1d..d0183e65b1bc62c326258f3ea759147e81bb5614 100644
--- a/2022/src/main/java/edu/unl/cse/bohn/year2022/Day9.java
+++ b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day9.java
@@ -9,45 +9,67 @@ import java.util.stream.IntStream;
 
 @SuppressWarnings("unused")
 public class Day9 extends Puzzle {
+    @SuppressWarnings("CommentedOutCode")
     public Day9(boolean isProductionReady) {
         super(isProductionReady);
+//        sampleData = """
+//                R 4
+//                U 4
+//                L 3
+//                D 1
+//                R 4
+//                D 1
+//                L 5
+//                R 2""";
         sampleData = """
-                R 4
-                U 4
-                L 3
-                D 1
-                R 4
-                D 1
-                L 5
-                R 2""";
+                R 5
+                U 8
+                L 8
+                D 3
+                R 17
+                D 10
+                L 25
+                U 20""";
     }
 
     @Override
     public long computePart1(List<String> data) {
         List<Character> movements = extractIndividualMovements(data);
         int totalDistanceTravelled = movements.size();
+        boolean[][] visitedLocations = manipulateRope(movements, totalDistanceTravelled, 2);
+        return countVisitedLocations(visitedLocations);
+    }
+
+    @Override
+    public long computePart2(List<String> data) {
+        List<Character> movements = extractIndividualMovements(data);
+        int totalDistanceTravelled = movements.size();
+        boolean[][] visitedLocations = manipulateRope(movements, totalDistanceTravelled, 10);
+        return countVisitedLocations(visitedLocations);
+    }
+
+    private static boolean[][] manipulateRope(List<Character> movements,
+                                              int totalDistanceTravelled,
+                                              int numberOfKnots) {
         boolean[][] visitedLocations = new boolean[2 * totalDistanceTravelled][2 * totalDistanceTravelled];
         Arrays.stream(visitedLocations).forEach(row -> Arrays.fill(row, false));
-        Position head = new Position(totalDistanceTravelled, totalDistanceTravelled);
-        Position tail = new Position(totalDistanceTravelled, totalDistanceTravelled);
-        visitedLocations[tail.row][tail.column] = true;
+        Position[] knots = new Position[numberOfKnots];
+        Arrays.fill(knots, new Position(totalDistanceTravelled, totalDistanceTravelled));
+        visitedLocations[knots[numberOfKnots - 1].row][knots[numberOfKnots - 1].column] = true;
         for (Character movement : movements) {
-            head = switch (movement) {
-                case 'R' -> new Position(head.row, head.column + 1);
-                case 'L' -> new Position(head.row, head.column - 1);
-                case 'U' -> new Position(head.row + 1, head.column);
-                case 'D' -> new Position(head.row - 1, head.column);
+            knots[0] = switch (movement) {
+                case 'R' -> new Position(knots[0].row, knots[0].column + 1);
+                case 'L' -> new Position(knots[0].row, knots[0].column - 1);
+                case 'U' -> new Position(knots[0].row + 1, knots[0].column);
+                case 'D' -> new Position(knots[0].row - 1, knots[0].column);
                 default -> throw new IllegalStateException("Unrecognized movement: " + movement);
             };
-            tail = tail.moveToward(head);
-            visitedLocations[tail.row][tail.column] = true;
+            for (int i = 1; i < numberOfKnots; i++) {
+                knots[i] = knots[i].moveToward(knots[i-1]);
+            }
+            visitedLocations[knots[numberOfKnots - 1].row][knots[numberOfKnots - 1].column] = true;
         }
-        return countVisitedLocations(visitedLocations);
-    }
-
-    @Override
-    public long computePart2(List<String> data) {
-        return 0;
+        return visitedLocations;
     }
 
     private record Position(int row, int column) {