You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

51 lines
1.8 KiB
Clojure

(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)))))