From 8e24234f5393eb84515207fa1e8ca0dfe86aea9c Mon Sep 17 00:00:00 2001
From: Christopher Bohn <bohn@unl.edu>
Date: Sun, 12 Dec 2021 17:16:02 -0600
Subject: [PATCH] Day 5 complete

---
 2021/README.md                                |  16 ++-
 2021/src/main/java/edu/unl/cse/bohn/Main.java |   4 +-
 .../main/java/edu/unl/cse/bohn/Puzzle.java    |   7 +-
 .../java/edu/unl/cse/bohn/year2021/Day1.java  |   5 +-
 .../java/edu/unl/cse/bohn/year2021/Day2.java  |   5 +-
 .../java/edu/unl/cse/bohn/year2021/Day3.java  |   5 +-
 .../java/edu/unl/cse/bohn/year2021/Day4.java  |   5 +-
 .../java/edu/unl/cse/bohn/year2021/Day5.java  | 108 ++++++++++++++++++
 8 files changed, 138 insertions(+), 17 deletions(-)
 create mode 100644 2021/src/main/java/edu/unl/cse/bohn/year2021/Day5.java

diff --git a/2021/README.md b/2021/README.md
index 9f4b90a..7290326 100644
--- a/2021/README.md
+++ b/2021/README.md
@@ -21,4 +21,18 @@ masks are cool.
 This problem is a little more interesting since there are two stringly types in
 the data, and one of them (the Bingo cards) requires a delimiter between
 instances. Defining a custom class to represent Bingo cards simplifies the
-post-parsing problem.
\ No newline at end of file
+post-parsing problem.
+
+## Day 5
+
+This is a pretty straight-forward problem. The only real challenge is that there
+are two significant sub-problems: computing the line segments and computing the
+vent map. I suppose an alternative approach would be to compute the y=mx+b form
+of the lines and algebraically determining their intersections.
+
+I definitely need to get into the habit of thinking about computationally
+less-complex approaches. The straight-forward design I came up with for Day 5 is
+O(num_lines * num_rows * num_columns); the algebraic approach would be 
+O(num_lines^2), so not too much of a big deal on this problem. But (I'm sure)
+there will be some problems whose straight-forward solution are a tad 
+intractable. 
\ No newline at end of file
diff --git a/2021/src/main/java/edu/unl/cse/bohn/Main.java b/2021/src/main/java/edu/unl/cse/bohn/Main.java
index f2d082f..c1a7573 100644
--- a/2021/src/main/java/edu/unl/cse/bohn/Main.java
+++ b/2021/src/main/java/edu/unl/cse/bohn/Main.java
@@ -21,13 +21,13 @@ public class Main {
                 Integer.toString(calendar.get(Calendar.YEAR)), scanner));
         int day = Integer.parseInt(getUserInput("Enter puzzle day",
                 Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)), scanner));
+        boolean useProductionData = getUserInput("Use sample data (Y/N)?", "Y", scanner).toUpperCase().charAt(0) != 'Y';
         scanner.close();
         ImportData dataSource = new ImportData(apiKey, year, day);
         String className = Main.class.getPackageName() + ".year" + year + ".Day" + day;
         Puzzle puzzle = null;
         try {
-            puzzle = (Puzzle)Class.forName(className).getConstructors()[0]
-                    .newInstance();
+            puzzle = (Puzzle)Class.forName(className).getConstructors()[0].newInstance(useProductionData);
         } catch (ClassNotFoundException classNotFoundException) {
             System.err.println("Could not find class " + className);
             System.exit(1);
diff --git a/2021/src/main/java/edu/unl/cse/bohn/Puzzle.java b/2021/src/main/java/edu/unl/cse/bohn/Puzzle.java
index ef977db..b8e5910 100644
--- a/2021/src/main/java/edu/unl/cse/bohn/Puzzle.java
+++ b/2021/src/main/java/edu/unl/cse/bohn/Puzzle.java
@@ -4,9 +4,12 @@ import java.io.IOException;
 import java.util.List;
 
 public abstract class Puzzle {
-    protected Integer day = null;
     protected String sampleData = "";
-    protected boolean isProductionReady = false;
+    protected boolean isProductionReady;
+
+    public Puzzle(boolean isProductionReady) {
+        this.isProductionReady = isProductionReady;
+    }
 
     public abstract int computePart1(List<String> data);
     public abstract int computePart2(List<String> data);
diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day1.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day1.java
index a19ed99..e1b1be5 100644
--- a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day1.java
+++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day1.java
@@ -9,8 +9,8 @@ import java.util.List;
 public class Day1 extends Puzzle {
     private List<Integer> depths;
 
-    public Day1() {
-        day = 1;
+    public Day1(boolean isProductionReady) {
+        super(isProductionReady);
         sampleData = """
                 199
                 200
@@ -22,7 +22,6 @@ public class Day1 extends Puzzle {
                 269
                 260
                 263""";
-        isProductionReady = true;
     }
 
     private int countIncreases(List<Integer> values) {
diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day2.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day2.java
index 43ef3f3..92585ee 100644
--- a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day2.java
+++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day2.java
@@ -16,8 +16,8 @@ public class Day2 extends Puzzle {
     @SuppressWarnings("FieldCanBeLocal")
     private int aim;
 
-    public Day2() {
-        day = 2;
+    public Day2(boolean isProductionReady) {
+        super(isProductionReady);
         sampleData = """
                 forward 5
                 down 5
@@ -25,7 +25,6 @@ public class Day2 extends Puzzle {
                 up 3
                 down 8
                 forward 2""";
-        isProductionReady = true;
     }
 
     @Override
diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day3.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day3.java
index 292ead5..fa94aab 100644
--- a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day3.java
+++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day3.java
@@ -12,8 +12,8 @@ public class Day3 extends Puzzle {
     private int reportLength;
     private int[] ones, zeroes;
 
-    public Day3() {
-        day = 3;
+    public Day3(boolean isProductionReady) {
+        super(isProductionReady);
         sampleData = """
                 00100
                 11110
@@ -27,7 +27,6 @@ public class Day3 extends Puzzle {
                 11001
                 00010
                 01010""";
-        isProductionReady = true;
     }
 
     @Override
diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day4.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day4.java
index 27b1ee3..46fa1c2 100644
--- a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day4.java
+++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day4.java
@@ -13,8 +13,8 @@ public class Day4 extends Puzzle {
     private List<Integer> numbers;
     private List<BingoCard> cards;
 
-    public Day4() {
-        day = 4;
+    public Day4(boolean isProductionReady) {
+        super(isProductionReady);
         sampleData = """
                 7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1
                                 
@@ -35,7 +35,6 @@ public class Day4 extends Puzzle {
                 18  8 23 26 20
                 22 11 13  6  5
                  2  0 12  3  7""";
-        isProductionReady = true;
     }
 
     private void parseData(List<String> data) {
diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day5.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day5.java
new file mode 100644
index 0000000..21a443d
--- /dev/null
+++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day5.java
@@ -0,0 +1,108 @@
+package edu.unl.cse.bohn.year2021;
+
+import edu.unl.cse.bohn.Puzzle;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+@SuppressWarnings("unused")
+public class Day5 extends Puzzle {
+    public record Point(int x, int y) {
+    }
+
+    List<List<Point>> lineSegments;
+    int greatestX, greatestY;
+
+    public Day5(boolean isProductionReady) {
+        super(isProductionReady);
+        sampleData = """
+                0,9 -> 5,9
+                8,0 -> 0,8
+                9,4 -> 3,4
+                2,2 -> 2,1
+                7,0 -> 7,4
+                6,4 -> 2,0
+                0,9 -> 2,9
+                3,4 -> 1,4
+                0,0 -> 8,8
+                5,5 -> 8,2""";
+    }
+
+    private void parseData(List<String> data, boolean considerDiagonals) {
+        greatestX = greatestY = 0;
+        lineSegments = new LinkedList<>();
+        for (String datum : data) {
+            List<Point> lineSegment = new LinkedList<>();
+            String[] endPoints = datum.split(" -> ");
+            String[] point = endPoints[0].split(",");
+            int x1 = Integer.parseInt(point[0]);
+            int y1 = Integer.parseInt(point[1]);
+            point = endPoints[1].split(",");
+            int x2 = Integer.parseInt(point[0]);
+            int y2 = Integer.parseInt(point[1]);
+            greatestX = Integer.max(greatestX, Integer.max(x1, x2));
+            greatestY = Integer.max(greatestY, Integer.max(y1, y2));
+            if (x1 == x2) {             // vertical line
+                int yMin = Integer.min(y1, y2);
+                int yMax = Integer.max(y1, y2);
+                for (int y = yMin; y <= yMax; y++) {
+                    lineSegment.add(new Point(x1, y));
+                }
+            } else if (y1 == y2) {      // horizontal line
+                int xMin = Integer.min(x1, x2);
+                int xMax = Integer.max(x1, x2);
+                for (int x = xMin; x <= xMax; x++) {
+                    lineSegment.add(new Point(x, y1));
+                }
+            } else if (considerDiagonals) {
+                int y = y1;
+                if (x1 < x2) {
+                    for (int x = x1; x <= x2; x++) {
+                        lineSegment.add(new Point(x,y));
+                        y = y1 < y2 ? y+1 : y-1;
+                    }
+                } else {
+                    for (int x = x1; x >= x2; x--) {
+                        lineSegment.add(new Point(x,y));
+                        y = y1 < y2 ? y+1 : y-1;
+                    }
+                }
+            }
+            lineSegments.add(lineSegment);
+        }
+    }
+
+    private int countIntersectingVentLines() {
+        int[][] ventMap = new int[greatestX + 1][greatestY + 1];
+        for (int[] row : ventMap) {
+            Arrays.fill(row, 0);
+        }
+        for (List<Point> lineSegment : lineSegments) {
+            for (Point point : lineSegment) {
+                ventMap[point.x()][point.y()]++;
+            }
+        }
+        int numberOfIntersections = 0;
+        for (int x = 0; x <= greatestX; x++) {
+            for (int y = 0; y <= greatestY; y++) {
+                if (ventMap[x][y] > 1) {
+                    numberOfIntersections++;
+                }
+            }
+        }
+        return numberOfIntersections;
+    }
+
+    @Override
+    public int computePart1(List<String> data) {
+        parseData(data, false);
+        return countIntersectingVentLines();
+    }
+
+    @Override
+    public int computePart2(List<String> data) {
+        parseData(data, true);
+        return countIntersectingVentLines();
+    }
+}
-- 
GitLab