From ab35275f17d199765a0eee89782303b67956570a Mon Sep 17 00:00:00 2001
From: Christopher Bohn <bohn@unl.edu>
Date: Fri, 17 Dec 2021 22:24:33 -0600
Subject: [PATCH] Day 14 complete

---
 2021/README.md                                | 12 ++-
 .../java/edu/unl/cse/bohn/year2021/Day14.java | 97 +++++++------------
 2 files changed, 45 insertions(+), 64 deletions(-)

diff --git a/2021/README.md b/2021/README.md
index b5d150c..c38c2a6 100644
--- a/2021/README.md
+++ b/2021/README.md
@@ -201,8 +201,14 @@ everything: memory management was definitely a HUGE constant factor. Keeping
 track of the positions of each element in the polymer will use very, very little
 memory.
 
-Yup, this has definitely slowed down computation. And, now that I think about it,
-I have to create as many indices as the original string's length was. This isn't
-a savings. At. All.
+Yup, this has definitely slowed down computation. And, now that I think about
+it, I have to create as many indices as the original string's length was. This 
+isn't a savings. At. All.
 
 What am I missing?
+
+Let's try it this way: I don't need to keep track of the molecule *at all*. If
+I keep track of the number of occurrences of each pair, then the numbers of
+occurrences will grow and shrink in each iteration.
+
+Yup. That did it.
diff --git a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java
index 6cc4c91..f0edcb9 100644
--- a/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java
+++ b/2021/src/main/java/edu/unl/cse/bohn/year2021/Day14.java
@@ -3,14 +3,14 @@ package edu.unl.cse.bohn.year2021;
 import edu.unl.cse.bohn.Puzzle;
 
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 
 @SuppressWarnings("unused")
 public class Day14 extends Puzzle {
-    private Map<String, Character> rules;
+    private Map<String, String> rules;
+    private Map<String, AtomicLong> patterns;
 
     public Day14(boolean isProductionReady) {
         super(isProductionReady);
@@ -38,78 +38,53 @@ public class Day14 extends Puzzle {
     private String parseData(List<String> data) {
         String initialMolecule = data.get(0);
         rules = new HashMap<>();
+        patterns = new HashMap<>();
         for (String rule : data) {
             if (rule.contains(" -> ")) {
                 String[] halves = rule.split(" -> ");
-                rules.put(halves[0], halves[1].charAt(0));
+                rules.put(halves[0], halves[1]);
+                patterns.put(halves[0], new AtomicLong(0L));
             }
         }
+        for (int i = 0; i < initialMolecule.length() - 1; i++) {
+            patterns.get(initialMolecule.substring(i, i + 2)).getAndIncrement();
+        }
         return initialMolecule;
     }
 
     private long producePolymer(List<String> data, int numberOfSteps) {
-        Map<Character, List<AtomicLong>> molecule = new HashMap<>();
-        long index = 0;
-        for (char element : parseData(data).toCharArray()) {
-            if (!molecule.containsKey(element)) {
-                molecule.put(element, new LinkedList<>());
-            }
-            molecule.get(element).add(new AtomicLong(index++));
-        }
-        for (char element : molecule.keySet()) {
-            System.out.println("\t\t" + element + ": " + molecule.get(element));
-        }
+        String molecule = parseData(data);
+        String tail = molecule.substring(molecule.length() - 2);
+        Map<String, Long> newValues = new HashMap<>();
         for (int i = 0; i < numberOfSteps; i++) {
-            System.out.println("\tGrowing...\t" + i);
-            growMolecule(molecule);
-            if (i < 4) {
-                for (char element : molecule.keySet()) {
-                    System.out.println("\t\t" + element + ": " + molecule.get(element));
-                }
+            for (String pattern : patterns.keySet()) {
+                newValues.put(pattern, 0L);
             }
-        }
-        long leastFrequentOccurrence = molecule.keySet().stream()
-                .mapToLong(element -> molecule.get(element).size()).min().orElseThrow();
-        long mostFrequentOccurrence = molecule.keySet().stream()
-                .mapToLong(element -> molecule.get(element).size()).max().orElseThrow();
-        return mostFrequentOccurrence - leastFrequentOccurrence;
-    }
-
-    private Character getCharAt(Map<Character, List<AtomicLong>> molecule, long index) {
-        return molecule.keySet().stream()
-                .filter(e -> molecule.get(e).stream().anyMatch(position -> position.get() == index))
-                .findFirst().orElse(null);
-    }
-
-    private void incrementIndicesAfter(Map<Character, List<AtomicLong>> molecule, long start) {
-        for (char element : molecule.keySet()) {
-            molecule.get(element).stream()
-                    .filter(position -> start <= position.get())
-                    .forEach(AtomicLong::getAndIncrement);
-        }
-    }
-
-    @SuppressWarnings("UnusedReturnValue")
-    private Map<Character, List<AtomicLong>> growMolecule(Map<Character, List<AtomicLong>> molecule) {
-        boolean stillGrowing = true;
-        long index = 0;
-        char[] pattern = {getCharAt(molecule, index), getCharAt(molecule, ++index)};
-        do {
-            incrementIndicesAfter(molecule, index);
-            char newElement = rules.get(new String(pattern));
-            if (!molecule.containsKey(newElement)) {
-                molecule.put(newElement, new LinkedList<>());
+            for (String pattern : patterns.keySet()) {
+                String newPattern = pattern.charAt(0) + rules.get(pattern);
+                newValues.put(newPattern, newValues.get(newPattern) + patterns.get(pattern).longValue());
+                newPattern = rules.get(pattern) + pattern.charAt(1);
+                newValues.put(newPattern, newValues.get(newPattern) + patterns.get(pattern).longValue());
             }
-            molecule.get(newElement).add(new AtomicLong(index++));
-            Character nextElement = getCharAt(molecule, ++index);
-            if (nextElement == null) {
-                stillGrowing = false;
-            } else {
-                pattern[0] = pattern[1];
-                pattern[1] = nextElement;
+            for (String pattern : patterns.keySet()) {
+                patterns.get(pattern).set(newValues.get(pattern));
             }
-        } while (stillGrowing);
-        return molecule;
+            tail = rules.get(tail) + tail.charAt(1);
+        }
+        Map<Character, AtomicLong> elementCounts = new HashMap<>();
+        elementCounts.put(tail.charAt(1), new AtomicLong(1L));
+        for (String pattern : patterns.keySet()) {
+            char element = pattern.charAt(0);
+            if (!elementCounts.containsKey(element)) {
+                elementCounts.put(element, new AtomicLong(0L));
+            }
+            elementCounts.get(element).getAndAdd(patterns.get(pattern).longValue());
+        }
+        long leastCommon = elementCounts.keySet().stream()
+                .mapToLong(element -> elementCounts.get(element).longValue()).min().orElseThrow();
+        long mostCommon = elementCounts.keySet().stream()
+                .mapToLong(element -> elementCounts.get(element).longValue()).max().orElseThrow();
+        return mostCommon - leastCommon;
     }
 
     @Override
-- 
GitLab