From fc6bff03e09191af164f6cc9e6e016db6f91fd44 Mon Sep 17 00:00:00 2001
From: Christopher Bohn <bohn@unl.edu>
Date: Fri, 9 Dec 2022 09:51:20 -0600
Subject: [PATCH] Completed Year 2022 Day 9 part 1

---
 2022/README.md                                |   7 +-
 .../java/edu/unl/cse/bohn/year2022/Day9.java  | 100 ++++++++++++++++++
 2 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 2022/src/main/java/edu/unl/cse/bohn/year2022/Day9.java

diff --git a/2022/README.md b/2022/README.md
index b0c0ae5..6f32678 100644
--- a/2022/README.md
+++ b/2022/README.md
@@ -258,7 +258,12 @@ Well... I'm going to take the part 2 code in a (very) slightly different directi
 ### Part 1
 
 The subproblems are
-- ...
+- Determine whether the head and tail are touching
+- Determine what direction the tail should move
+- Both of the previous subproblems include the subproblem of finding the distance between the head and tail along each
+  dimension
+- Track which locations the tail has visited
+- Count those locations
 
 ### Part 2
 
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
new file mode 100644
index 0000000..ecb6ad8
--- /dev/null
+++ b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day9.java
@@ -0,0 +1,100 @@
+package edu.unl.cse.bohn.year2022;
+
+import edu.unl.cse.bohn.Puzzle;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.IntStream;
+
+@SuppressWarnings("unused")
+public class Day9 extends Puzzle {
+    public Day9(boolean isProductionReady) {
+        super(isProductionReady);
+        sampleData = """
+                R 4
+                U 4
+                L 3
+                D 1
+                R 4
+                D 1
+                L 5
+                R 2""";
+    }
+
+    @Override
+    public long computePart1(List<String> data) {
+        List<Character> movements = extractIndividualMovements(data);
+        int totalDistanceTravelled = movements.size();
+        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;
+        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);
+                default -> throw new IllegalStateException("Unrecognized movement: " + movement);
+            };
+            tail = tail.moveToward(head);
+            visitedLocations[tail.row][tail.column] = true;
+        }
+        return countVisitedLocations(visitedLocations);
+    }
+
+    @Override
+    public long computePart2(List<String> data) {
+        return 0;
+    }
+
+    private record Position(int row, int column) {
+        public Position moveToward(Position destination) {
+            int rowDifference = destination.row - this.row;
+            int columnDifference = destination.column - this.column;
+            if (Math.abs(rowDifference) <= 1 && Math.abs(columnDifference) <= 1) {
+                return this;
+            } else if (rowDifference == 0) {
+                return new Position(row, (columnDifference > 0) ? column + 1 : column - 1);
+            } else if (columnDifference == 0) {
+                return new Position((rowDifference > 0) ? row + 1 : row - 1, column);
+            } else {
+                return new Position(
+                        (rowDifference > 0) ? row + 1 : row - 1,
+                        (columnDifference > 0) ? column + 1 : column - 1
+                );
+            }
+        }
+    }
+
+    private List<Character> extractIndividualMovements(List<String> data) {
+        List<Character> movements = new LinkedList<>();
+        for (String datum : data) {
+            char direction = datum.charAt(0);
+            int distance = Integer.parseInt(datum.substring(2));
+            IntStream.range(0, distance).mapToObj(i -> direction).forEach(movements::add);
+        }
+        return movements;
+    }
+
+    private long countVisitedLocations(boolean[][] visitedLocations) {
+        int numberOfVisitedLocations = 0;
+        for (boolean[] visitedRow : visitedLocations) {
+            for (boolean visitedLocation : visitedRow) {
+                numberOfVisitedLocations += visitedLocation ? 1 : 0;
+            }
+        }
+        return numberOfVisitedLocations;
+    }
+
+    private void printLocations(boolean[][] locations) {
+        for (boolean[] row : locations) {
+            for (boolean location : row) {
+                System.out.print(location ? '#' : '.');
+            }
+            System.out.println();
+        }
+    }
+}
-- 
GitLab