diff --git a/2021/README.md b/2021/README.md index 6669c6d21f383e17952a98bd6ebd9b02d9d4c7c8..c31634ce6cf4d0014af6e91e8231a8008ae30b33 100644 --- a/2021/README.md +++ b/2021/README.md @@ -148,3 +148,20 @@ for part 2, but we shall see... Good news! I was wrong about needing to build the cave graph for part 2. I just need to specialize my `Cave` inner class to change the rules for adding children. + +# Day 13 + +This looks straight-forward. No fancy data structures required. No clever +re-framing the problem, either. Creating the "paper" requires a couple of steps +but no big deal. + +Hmm... part 1 took longer than I think it should have. The big-O complexity is +manageable, but I guess the constant factors are problematic. + +For part 2, I'm not even going to try to algorithmically determine which letters +are created (and not just because I'd have to return soemthing other than a +long integer). + +Hmm... part 2 really didn't take much longer than part 1 did, which suggests +the computational pain point is in parsing the data and creating the "paper" +and not in the folding. diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day13.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day13.java new file mode 100644 index 0000000000000000000000000000000000000000..19a2497b8cb09c526de171b381076af1b5bbe359 --- /dev/null +++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day13.java @@ -0,0 +1,150 @@ +package edu.unl.cse.bohn.year2021; + +import edu.unl.cse.bohn.Puzzle; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +@SuppressWarnings("unused") +public class Day13 extends Puzzle { + public record Point(int x, int y) { + public Point(String coordinates) { + this(Integer.parseInt(coordinates.split(",")[0]), Integer.parseInt(coordinates.split(",")[1])); + } + } + + private List<String> folds; + private boolean[][] paper; + + public Day13(boolean isProductionReady) { + super(isProductionReady); + sampleData = """ + 6,10 + 0,14 + 9,10 + 0,3 + 10,4 + 4,11 + 6,0 + 6,12 + 4,1 + 0,13 + 10,12 + 3,4 + 3,0 + 8,4 + 1,10 + 2,14 + 8,10 + 9,0 + + fold along y=7 + fold along x=5"""; + } + + private void parseInput(List<String> data) { + int maximumX = Integer.MIN_VALUE, maximumY = Integer.MIN_VALUE; + Set<Point> points = new HashSet<>(); + folds = new LinkedList<>(); + int lineNumber = 0; + do { + Point point = new Point(data.get(lineNumber++)); + points.add(point); + maximumX = Integer.max(maximumX, point.x()); + maximumY = Integer.max(maximumY, point.y()); + } while (!data.get(lineNumber).equals("")); + for (++lineNumber; lineNumber < data.size(); lineNumber++) { + String line = data.get(lineNumber); + folds.add(line.substring(line.lastIndexOf(' ') + 1)); + } + paper = new boolean[maximumX + 1][maximumY + 1]; + for (int i = 0; i < paper.length; i++) { + for (int j = 0; j < paper[i].length; j++) { + int x = i; + int y = j; + paper[x][y] = points.stream().anyMatch(point -> point.x() == x && point.y() == y); + } + } + } + + @SuppressWarnings("DuplicatedCode") + private void foldPaper(String fold) { + int originalWidth = paper.length; + int originalHeight = paper[0].length; + char dimension = fold.charAt(0); + int seam = Integer.parseInt(fold.substring(2)); + boolean[][] foldedPaper; + switch (dimension) { + case 'x' -> { + foldedPaper = new boolean[seam][originalHeight]; + for (int x = 0; x < originalWidth; x++) { + for (int y = 0; y < originalHeight; y++) { + if (x < seam) { + foldedPaper[x][y] = paper[x][y]; + } else if (x > seam) { + int mirrorX = seam - (x - seam); + foldedPaper[mirrorX][y] = foldedPaper[mirrorX][y] || paper[x][y]; + } + } + } + } + case 'y' -> { + foldedPaper = new boolean[originalWidth][seam]; + for (int x = 0; x < originalWidth; x++) { + for (int y = 0; y < originalHeight; y++) { + if (y < seam) { + foldedPaper[x][y] = paper[x][y]; + } else if (y > seam) { + int mirrorY = seam - (y - seam); + foldedPaper[x][mirrorY] = foldedPaper[x][mirrorY] || paper[x][y]; + } + } + } + } + default -> throw new IllegalArgumentException("Unexpected fold dimension: " + fold); + } + paper = foldedPaper; + } + + private long countDots() { + long numberOfDots = 0; + for (boolean[] row : paper) { + for (boolean hasAPoint : row) { + if (hasAPoint) { + numberOfDots++; + } + } + } + return numberOfDots; + } + + private void printDots() { + // transpose array + for (int j = 0; j < paper[0].length; j++) { + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < paper.length; i++) { // goodbye cache friendliness + System.out.print(paper[i][j] ? '#' : ' '); + } + System.out.println(); + } + } + + @Override + public long computePart1(List<String> data) { + parseInput(data); + foldPaper(folds.get(0)); + return countDots(); + } + + @Override + public long computePart2(List<String> data) { + parseInput(data); // reset everything + for (String fold : folds) { + foldPaper(fold); + } + printDots(); + return 0; + } +}