From 8d43e37df99f280377bed90284d6ac2428334804 Mon Sep 17 00:00:00 2001
From: Clyne Sullivan <clyne@bitgloo.com>
Date: Wed, 30 Nov 2022 19:55:31 -0500
Subject: move 2021 days to folder; update README

---
 year2021/day19/partboth.clj | 98 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 year2021/day19/partboth.clj

(limited to 'year2021/day19')

diff --git a/year2021/day19/partboth.clj b/year2021/day19/partboth.clj
new file mode 100644
index 0000000..48f1a9c
--- /dev/null
+++ b/year2021/day19/partboth.clj
@@ -0,0 +1,98 @@
+(require '[clojure.core.reducers :as r])
+(require 'clojure.string)
+
+(def orientation-vectors
+  [[[1 0 0]  [0 1 0]  [0 0 1]]
+   [[1 0 0]  [0 0 -1] [0 1 0]]
+   [[1 0 0]  [0 -1 0] [0 0 -1]]
+   [[1 0 0]  [0 0 1]  [0 -1 0]]
+   [[-1 0 0] [0 -1 0] [0 0 1]]
+   [[-1 0 0] [0 0 -1] [0 -1 0]]
+   [[-1 0 0] [0 1 0]  [0 0 -1]]
+   [[-1 0 0] [0 0 1]  [0 1 0]]
+   [[0 0 -1] [1 0 0]  [0 -1 0]]
+   [[0 1 0]  [1 0 0]  [0 0 -1]]
+   [[0 0 1]  [1 0 0]  [0 1 0]]
+   [[0 -1 0] [1 0 0]  [0 0 1]]
+   [[0 0 1]  [-1 0 0] [0 -1 0]]
+   [[0 1 0]  [-1 0 0] [0 0 1]]
+   [[0 0 -1] [-1 0 0] [0 1 0]]
+   [[0 -1 0] [-1 0 0] [0 0 -1]]
+   [[0 -1 0] [0 0 -1] [1 0 0]]
+   [[0 0 1]  [0 -1 0] [1 0 0]]
+   [[0 1 0]  [0 0 1]  [1 0 0]]
+   [[0 0 -1] [0 1 0]  [1 0 0]]
+   [[0 0 1]  [0 1 0]  [-1 0 0]]
+   [[0 -1 0] [0 0 1]  [-1 0 0]]
+   [[0 0 -1] [0 -1 0] [-1 0 0]]
+   [[0 1 0]  [0 0 -1] [-1 0 0]]])
+
+(defn build-scanner-reports
+  "Splits slurped, split-line'd input by scanner."
+  [input-lines]
+  (loop [scanners [] rem-input input-lines]
+    (if (empty? rem-input)
+      scanners
+      (let [[this nxt] (split-with (comp not empty?) rem-input)]
+        (recur (->> (rest this)
+                    (map #(read-string (clojure.string/join ["[" % "]"])))
+                    (conj scanners))
+               (rest nxt))))))
+
+(defn point-add [[a b c] [d e f]] [(+ a d) (+ b e) (+ c f)])
+
+(defn orient [[x y z] [[a b c] [d e f] [g h i]]]
+  [(+ (* x a) (* y d) (* z g)) (+ (* x b) (* y e) (* z h)) (+ (* x c) (* y f) (* z i))])
+
+(defn scanner-orientation [report or-index]
+  (map #(orient (map - %) (get orientation-vectors or-index)) report))
+
+(defn scanner-orientations
+  "Builds list of scanner reports adjusted for all possible orientations."
+  [report]
+  (for [or-vec orientation-vectors]
+    (map #(orient (map - %) or-vec) report)))
+
+(defn scanner-build-potential-links
+  "Builds a list for each s2 orientation that contains lists of each s1 point
+   added to the corresponding s2 point."
+  [s1 s2]
+  (for [s2-or (scanner-orientations s2)]
+    (for [i (range 0 (count s1))]
+      (for [j (range 0 (count s2-or))]
+        (point-add (nth s1 i) (nth s2-or j))))))
+
+(defn scanner-find-connection
+  "Attempt to determine if s1 and s2 are linked through common beacons."
+  [s1 s2]
+  (loop [potential-links (as-> (scanner-build-potential-links s1 s2) $
+                               (for [i (range 0 (count $))] [i (nth $ i)])
+                               (into [] $))]
+    (when-let [[orientation link] (first potential-links)]
+      (if-let [match (first (drop-while #(< (val %) 12) (frequencies (reduce concat link))))]
+        [orientation (key match)]
+        (recur (rest potential-links))))))
+
+(defn scanner-merge
+  "Merges the report of linked scanner s2 into scanner s1."
+  [s1 s2 s2-or s2-coord]
+  (vec (into (set s1) (map #(point-add s2-coord (map - %)) (scanner-orientation s2 s2-or)))))
+
+(let [[beacon-count scanner-coords]
+      (loop [new-reps  (->> (slurp "./in") clojure.string/split-lines build-scanner-reports)
+             sc-coords '([0 0 0])
+             next-reps (rest new-reps)]
+        (if-let [next-rep (first next-reps)]
+          (if-let [[found-or found-coord] (scanner-find-connection (first new-reps) next-rep)]
+            (let [new-base    (scanner-merge (first new-reps) next-rep found-or found-coord)
+                  newest-reps (->> (assoc new-reps 0 new-base) (filterv (partial not= next-rep)))]
+              (println "found" found-coord)
+              (recur newest-reps (conj sc-coords found-coord) (rest newest-reps)))
+            (recur new-reps sc-coords (rest next-reps)))
+          [(count (first new-reps)) sc-coords]))]
+  (println "Part 1:" beacon-count)
+  (println "Part 2:"
+    (apply max
+      (for [p1 scanner-coords p2 scanner-coords :when (not= p1 p2)]
+        (apply + (map #(Math/abs %) (point-add (map - p1) p2)))))))
+
-- 
cgit v1.2.3