]> code.bitgloo.com Git - clyne/advent-of-code.git/commitdiff
day12: fast, parallel part 2
authorClyne Sullivan <clyne@bitgloo.com>
Mon, 13 Dec 2021 00:10:39 +0000 (19:10 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Mon, 13 Dec 2021 00:10:39 +0000 (19:10 -0500)
day12/part2.clj

index 0be59b7015de19808f215a8d4f04bef13aff4591..06b2bcd22129e5c6a677941dc45509f1a11a1a85 100644 (file)
@@ -1,48 +1,50 @@
-    (require '[clojure.string :as str])
-    
-    ; Build list of cave connections:
-    (def caves (->> (slurp "./in")
-               (str/split-lines)
-               (map #(str/split % #"-"))
-               (map (partial map str))
-               (#(concat % (map reverse %)))
-               ))
-    
-    ; Try to help execution speed by memoizing cave searches:
-    (def search-caves
-      (memoize (fn [id]
-        (filter #(= (first %) id) caves))))
-    
-    ; Given current path 'path', return a list of valid paths that branch
-    ; from 'path'. Note, paths are stored in reverse order.
-    (defn get-caves-forward [path]
-      (map #(cons (second %) path)
-        (filter
-          (fn [cv]
-            (and
-              ; Do not return to start
-              (not (str/starts-with? (second cv) "start"))
-              (or
-                ; Always allow uppercase paths
-                (< (int (first (second cv))) 96)
-                (let [lw (filter #(= (str/lower-case %) %) path)]
-                  (or
-                    ; Allow lowercase paths that have never been visited
-                    (= 0 (count (filter #(= % (second cv)) path)))
-                    ; Allow one duplicate if there are none yet
-                    (= 0 (- (count lw) (count (distinct lw)))))))))
-          ; Only work with paths that we connect to
-          (search-caves (first path))
-          )))
-    
-    (loop [paths (get-caves-forward ["start"]) complete-paths []]
-      (let [branches          (->> paths
-                                   (map get-caves-forward)
-                                   (apply concat))
-            complete-branches (concat complete-paths
-                                      (filter #(= (first %) "end") branches))
-            next-paths        (filter #(not= (first %) "end") branches)]
-        (if (empty? next-paths)
-          (println (count complete-branches))
-          (recur next-paths complete-branches))))
-    
+(require '[clojure.string :as str])
+(require '[clojure.core.reducers :as r])
+
+; Build list of cave connections:
+(def caves (->> (slurp "./in")
+           (str/split-lines)
+           (map #(str/split % #"-"))
+           (map (partial map str))
+           (#(concat % (map reverse %)))
+           ))
+
+; Try to help execution speed by memoizing cave searches:
+(def search-caves
+  (memoize (fn [id]
+    (filter
+      #(and (= (first %) id)
+            (not (str/starts-with? (second %) "start")))
+      caves
+      ))))
+
+; Given current path 'path', return a list of valid paths that branch
+; from 'path'. Note, paths are stored in reverse order.
+(defn get-caves-forward [path]
+  (r/map #(cons (second %) path)
+    (r/filter
+      (fn [cv]
+        (or
+          ; Always allow uppercase paths
+          (< (int (first (second cv))) 96)
+          ; Or, allow lowercase paths that have never been visited
+          (not-any? #(= % (second cv)) path)
+          ; Or, allow one duplicate if there are none yet
+          (apply distinct? (filter #(= (str/lower-case %) %) path))))
+      ; Only work with paths that we connect to
+      (search-caves (first path))
+      )))
+
+(loop [paths (into [] (get-caves-forward ["start"])) complete-paths 0]
+  (let [results (->> paths
+                     (r/mapcat get-caves-forward)
+                     (r/foldcat)
+                     (r/reduce
+                       (fn [r b] (if (not= (first b) "end")
+                                   (update r :next-paths #(conj % b))
+                                   (update r :complete-counts inc)))
+                       {:next-paths [] :complete-counts complete-paths}))]
+    (println (results :complete-counts))
+    (when-not (empty? (results :next-paths))
+      (recur (results :next-paths) (results :complete-counts)))))
+