]> code.bitgloo.com Git - clyne/advent-of-code.git/commitdiff
move 2021 days to folder; update README
authorClyne Sullivan <clyne@bitgloo.com>
Thu, 1 Dec 2022 00:55:31 +0000 (19:55 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Thu, 1 Dec 2022 00:55:31 +0000 (19:55 -0500)
103 files changed:
README.md
day1/part1.clj [deleted file]
day1/part2.clj [deleted file]
day10/part1.clj [deleted file]
day10/part2.clj [deleted file]
day10/partboth.clj [deleted file]
day11/part1.clj [deleted file]
day11/part2.clj [deleted file]
day12/part1.clj [deleted file]
day12/part2.clj [deleted file]
day13/part1.clj [deleted file]
day13/part2.clj [deleted file]
day13/partboth.clj [deleted file]
day14/part1.clj [deleted file]
day14/part2.clj [deleted file]
day15/part1.clj [deleted file]
day15/part2.clj [deleted file]
day16/part1.clj [deleted file]
day16/part2.cpp [deleted file]
day17/part3.clj [deleted file]
day17/partboth.clj [deleted file]
day18/partboth.clj [deleted file]
day19/partboth.clj [deleted file]
day2/part1.clj [deleted file]
day2/part2.clj [deleted file]
day20/partboth.clj [deleted file]
day21/part1.clj [deleted file]
day21/part2.clj [deleted file]
day22/part1.clj [deleted file]
day22/part2.clj [deleted file]
day23/part1-done-by-hand [deleted file]
day23/part2.clj [deleted file]
day24/checker.clj [deleted file]
day24/partboth.clj [deleted file]
day24/solved-by-hand-with-help.md [deleted file]
day25/part1.clj [deleted file]
day3/part1.clj [deleted file]
day3/part2.clj [deleted file]
day4/part1.clj [deleted file]
day4/part2.clj [deleted file]
day5/part1.clj [deleted file]
day5/part2.clj [deleted file]
day6/consteval.cpp [deleted file]
day6/part1.clj [deleted file]
day6/part2.clj [deleted file]
day7/maxima.mac [deleted file]
day7/part1.clj [deleted file]
day7/part2.clj [deleted file]
day8/part1.clj [deleted file]
day8/part2.clj [deleted file]
day9/part1.clj [deleted file]
day9/part2.clj [deleted file]
year2021/day1/part1.clj [new file with mode: 0644]
year2021/day1/part2.clj [new file with mode: 0644]
year2021/day10/part1.clj [new file with mode: 0644]
year2021/day10/part2.clj [new file with mode: 0644]
year2021/day10/partboth.clj [new file with mode: 0644]
year2021/day11/part1.clj [new file with mode: 0644]
year2021/day11/part2.clj [new file with mode: 0644]
year2021/day12/part1.clj [new file with mode: 0644]
year2021/day12/part2.clj [new file with mode: 0644]
year2021/day13/part1.clj [new file with mode: 0644]
year2021/day13/part2.clj [new file with mode: 0644]
year2021/day13/partboth.clj [new file with mode: 0644]
year2021/day14/part1.clj [new file with mode: 0644]
year2021/day14/part2.clj [new file with mode: 0644]
year2021/day15/part1.clj [new file with mode: 0644]
year2021/day15/part2.clj [new file with mode: 0644]
year2021/day16/part1.clj [new file with mode: 0644]
year2021/day16/part2.cpp [new file with mode: 0644]
year2021/day17/part3.clj [new file with mode: 0644]
year2021/day17/partboth.clj [new file with mode: 0644]
year2021/day18/partboth.clj [new file with mode: 0644]
year2021/day19/partboth.clj [new file with mode: 0644]
year2021/day2/part1.clj [new file with mode: 0644]
year2021/day2/part2.clj [new file with mode: 0644]
year2021/day20/partboth.clj [new file with mode: 0644]
year2021/day21/part1.clj [new file with mode: 0644]
year2021/day21/part2.clj [new file with mode: 0644]
year2021/day22/part1.clj [new file with mode: 0644]
year2021/day22/part2.clj [new file with mode: 0644]
year2021/day23/part1-done-by-hand [new file with mode: 0644]
year2021/day23/part2.clj [new file with mode: 0644]
year2021/day24/checker.clj [new file with mode: 0644]
year2021/day24/partboth.clj [new file with mode: 0644]
year2021/day24/solved-by-hand-with-help.md [new file with mode: 0644]
year2021/day25/part1.clj [new file with mode: 0644]
year2021/day3/part1.clj [new file with mode: 0644]
year2021/day3/part2.clj [new file with mode: 0644]
year2021/day4/part1.clj [new file with mode: 0644]
year2021/day4/part2.clj [new file with mode: 0644]
year2021/day5/part1.clj [new file with mode: 0644]
year2021/day5/part2.clj [new file with mode: 0644]
year2021/day6/consteval.cpp [new file with mode: 0644]
year2021/day6/part1.clj [new file with mode: 0644]
year2021/day6/part2.clj [new file with mode: 0644]
year2021/day7/maxima.mac [new file with mode: 0644]
year2021/day7/part1.clj [new file with mode: 0644]
year2021/day7/part2.clj [new file with mode: 0644]
year2021/day8/part1.clj [new file with mode: 0644]
year2021/day8/part2.clj [new file with mode: 0644]
year2021/day9/part1.clj [new file with mode: 0644]
year2021/day9/part2.clj [new file with mode: 0644]

index e0c4e582b32aefe0131d98c8ffa879fa6c8de3ed..9edc6dd3152d1262fbc2969eefdd8a1add3ea838 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,5 +1,13 @@
 # advent-of-code
 
-My Advent of Code answers, for 2021.
+My Advent of Code answers!
+
+**2022:**
+
+Scheme (either MIT-Scheme or Gambit) will most likely be my first choice. Forth is a runner-up, but probably too much to stick with.
+
+Day 1 will be attempted on an Apple ][ GS, using Applesoft BASIC.
+
+**2021:** Nearly all challenges were done in Clojure. I used C++ for a couple of the more challenging ones, and tried Maxima on a part too.
+**2020:** Incomplete, just tried a day in Clojure.
 
-Written in whatever language I feel like, likely Clojure or C++.
diff --git a/day1/part1.clj b/day1/part1.clj
deleted file mode 100644 (file)
index 1c2c756..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-; Day 1, part 1
-; Read a list of numbers from stdin, separated by newlines.
-; Count occurances of the current number being greater than
-; the previous.
-;
-
-(as-> (slurp "./in") $
-     (clojure.string/split-lines $)
-     (map read-string $)
-     (reduce
-       #(cond-> (assoc %1 0 %2) (> %2 (first %1)) (update 1 inc))
-       [(first $) 0]
-       (rest $))
-     (println (second $)))
-
diff --git a/day1/part2.clj b/day1/part2.clj
deleted file mode 100644 (file)
index e496c7d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-; Day 1, part 2
-; Read a list of numbers from stdin, separated by newlines.
-; Count occurances of the current sum being greater than
-; the previous, where a sum is that of the current number,
-; the previous number, and the next number.
-;
-
-(let [input (->> (slurp "./in")
-                 clojure.string/split-lines
-                 (mapv read-string))]
-  (println
-    (count
-      (filter #(< (get input %) (get input (+ % 3)))
-        (range 0 (- (count input) 3))))))
-
diff --git a/day10/part1.clj b/day10/part1.clj
deleted file mode 100644 (file)
index 60ed1e6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-(def to-closing {\{ \} \( \) \[ \] \< \>})
-(def to-score {\) 3 \] 57 \} 1197 \> 25137})
-
-(defn check-line [input]
-  (loop [in input open '()]
-    (when-let [c (first in)]
-      (if (some->> (#{\} \) \] \>} c) (not= (first open)))
-        c
-        (recur
-          (rest in)
-          (if-let [op (to-closing c)]
-            (conj open op)
-            (rest open)
-            ))))))
-
-(->> (slurp "./in")
-     (clojure.string/split-lines)
-     (map (comp to-score check-line vec))
-     (filter some?)
-     (apply +)
-     (println))
-
diff --git a/day10/part2.clj b/day10/part2.clj
deleted file mode 100644 (file)
index 4dfaf3b..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-(def to-closing {\{ \} \( \) \[ \] \< \>})
-(def to-score {\) 1 \] 2 \} 3 \> 4})
-
-(defn check-line [input]
-  (loop [in input open '()]
-    (if-let [c (first in)]
-      (when (or (nil? (#{\} \) \] \>} c)) (= (first open) c))
-        (recur
-          (rest in)
-          (if-let [op (to-closing c)]
-            (conj open op)
-            (rest open))))
-      open
-      )))
-
-(->> (slurp "./in")
-     (clojure.string/split-lines)
-     (map (comp check-line vec))
-     (filter some?)
-     (map (partial reduce #(+ (* 5 %1) (to-score %2)) 0))
-     (sort)
-     (#(nth % (quot (count %) 2)))
-     (println))
-
diff --git a/day10/partboth.clj b/day10/partboth.clj
deleted file mode 100644 (file)
index 78080d9..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-(def to-closing {\{ \} \( \) \[ \] \< \>})
-(def to-score {\) 3 \] 57 \} 1197 \> 25137})
-(def to-score2 {\) 1 \] 2 \} 3 \> 4})
-
-(defn check-line [input]
-  (loop [in input open '()]
-    (if-let [c (first in)]
-      (if (some->> (#{\} \) \] \>} c) (not= (first open)))
-        c
-        (recur
-          (rest in)
-          (if-let [op (to-closing c)]
-            (conj open op)
-            (rest open)
-            )))
-      open
-      )))
-
-(->> (slurp "./in")
-     (clojure.string/split-lines)
-     (map (comp check-line vec))
-     ; check-line returns first invalid character, or list of characters
-     ; necessary to close the line. Work through these through `reduce`
-     ; and build the answers for both parts:
-     (reduce
-       (fn [tots nxt]
-         (if (seq? nxt)
-           (update tots 1 #(conj % (reduce (fn [a b] (+ (* 5 a) (to-score2 b))) 0 nxt)))
-           (update tots 0 #(+ % (to-score nxt)))))
-       [0 '()])
-     ; Get part 2 answer from the list of scores:
-     (#(update % 1 (fn [ns] (nth ns (quot (count ns) 2)))))
-     (println))
-
diff --git a/day11/part1.clj b/day11/part1.clj
deleted file mode 100644 (file)
index 5113fd4..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-(defn get-adj [in y x]
-  (filter
-    #(some? (get-in in %))
-    [[(dec y) (dec x)] [(dec y) x] [(dec y) (inc x)]
-     [y (dec x)] [y (inc x)]
-     [(inc y) (dec x)] [(inc y) x] [(inc y) (inc x)]]
-    ))
-
-(defn apply-incs [in] (mapv (partial mapv inc) in))
-
-(defn next-step [indata]
-  (loop [in (apply-incs (indata :grid)) bl (indata :blinks) y 0 x 0]
-    (cond
-      (> (get-in in [y x]) 9)
-      (do
-        (recur
-          (-> (reduce
-                (fn [i n] (update-in i n #(cond-> % (pos? %) inc)))
-                in
-                (get-adj in y x))
-              (update-in [y x] #(do % 0)))
-          (inc bl)
-          0 0))
-      (< x (dec (count (first in))))
-      (recur in bl y (inc x))
-      (< y (dec (count in)))
-      (recur in bl (inc y) 0)
-      :else
-      {:grid in :blinks bl}
-      )
-    )
-  )
-
-(->> (slurp "./in")
-     (clojure.string/split-lines)
-     (map (partial map #(- (int %) 48)))
-     (assoc {} :blinks 0 :grid)
-     (iterate next-step)
-     (#(nth % 100))
-     (#(println (% :blinks))))
-
diff --git a/day11/part2.clj b/day11/part2.clj
deleted file mode 100644 (file)
index 4c4663c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-(defn get-adj [in y x]
-  (filter
-    #(some? (get-in in %))
-    [[(dec y) (dec x)] [(dec y) x] [(dec y) (inc x)]
-     [y (dec x)] [y (inc x)]
-     [(inc y) (dec x)] [(inc y) x] [(inc y) (inc x)]]
-    ))
-
-(defn apply-incs [in] (mapv (partial mapv inc) in))
-
-(defn next-step [indata]
-  (loop [in (apply-incs (indata :grid)) bl (indata :blinks) y 0 x 0]
-    (cond
-      (> (get-in in [y x]) 9)
-      (do
-        (recur
-          (-> (reduce
-                (fn [i n] (update-in i n #(cond-> % (pos? %) inc)))
-                in
-                (get-adj in y x))
-              (update-in [y x] #(do % 0)))
-          (inc bl)
-          0 0))
-      (< x (dec (count (first in))))
-      (recur in bl y (inc x))
-      (< y (dec (count in)))
-      (recur in bl (inc y) 0)
-      :else
-      {:grid in :blinks bl}
-      )
-    )
-  )
-
-(->> (slurp "./in")
-     (clojure.string/split-lines)
-     (map (partial map #(- (int %) 48)))
-     (assoc {} :blinks 0 :grid)
-     (iterate next-step)
-     (take-while #(pos? (apply + (flatten (% :grid)))))
-     (count)
-     (println))
-
diff --git a/day12/part1.clj b/day12/part1.clj
deleted file mode 100644 (file)
index cdd4a43..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-(require '[clojure.string :as str])
-
-(def caves (->> (slurp "./in")
-           (str/split-lines)
-           (map #(str/split % #"-"))
-           (map (partial map str))
-           (#(concat % (map reverse %)))
-           ))
-
-(defn get-caves-forward [klst]
-  (map #(cons (second %) klst)
-    (filter
-      #(or (< (int (first (second %))) 96)
-           (not-any? (partial = (second %)) klst))
-      (filter #(= (first %) (first klst)) caves)
-      )))
-
-(loop [lst (get-caves-forward ["start"]) ms '()]
-  (let [nxt (->> lst
-                 (map get-caves-forward)
-                 (apply concat))
-        mtchs  (concat ms (filter #(= (first %) "end") nxt))
-        nxtlst (filter #(not= (first %) "end") nxt)]
-    (if (empty? nxtlst)
-      (println (count mtchs))
-      (recur nxtlst mtchs))))
-
diff --git a/day12/part2.clj b/day12/part2.clj
deleted file mode 100644 (file)
index 06b2bcd..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-(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)))))
-
diff --git a/day13/part1.clj b/day13/part1.clj
deleted file mode 100644 (file)
index c3f08d4..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-(require '[clojure.string :as str])
-
-(def input (->> (slurp "./in")
-                (str/split-lines)
-                (split-with not-empty)
-                ((juxt
-                  (fn [lst]
-                    (reduce
-                      #(conj %1 (mapv read-string (str/split %2 #",")))
-                      #{} (first lst)))
-                  (fn [lst]
-                    (->> (second lst)
-                         (drop 1)
-                         (map #(-> %
-                                   (str/split #"=")
-                                   (update 0 (comp {\x 0 \y 1} last))
-                                   (update 1 read-string)))
-                         (first)
-                         ))))))
-
-(defn fold-point [idx chg pt]
-  (cond-> pt (> (get pt idx) chg) (update idx #(- % (* 2 (- % chg))))))
-
-(let [instruction (second input)]
-  (->> (first input)
-       (map (partial fold-point (first instruction) (second instruction)))
-       (distinct)
-       (count)
-       (println)))
-
diff --git a/day13/part2.clj b/day13/part2.clj
deleted file mode 100644 (file)
index 6db6555..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-(require '[clojure.string :as str])
-
-(def input (->> (slurp "./in")
-                (str/split-lines)
-                (split-with not-empty)
-                ((juxt
-                  (fn [lst]
-                    (reduce
-                      #(conj %1 (mapv read-string (str/split %2 #",")))
-                      #{} (first lst)))
-                  (fn [lst]
-                    (->> (rest (second lst))
-                         (map #(-> %
-                                   (str/split #"=")
-                                   (update 0 (comp {\x 0 \y 1} last))
-                                   (update 1 read-string)))
-                         ))))))
-
-(defn print-grid [pts]
-  (doseq [p pts] (println (str/join [(first p) "," (second p)]))))
-
-(defn fold-point [idx chg pt]
-  (cond-> pt (> (get pt idx) chg) (update idx #(- % (* 2 (- % chg))))))
-
-(print-grid
-  (apply
-    (partial
-      reduce
-      #(let [ins (first %2)]
-         (set (map (partial fold-point (first %2) (second %2)) %1))))
-    input
-    ))
-
diff --git a/day13/partboth.clj b/day13/partboth.clj
deleted file mode 100644 (file)
index c24980d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-(require '[clojure.string :as str])
-
-(def input (->> (slurp "./in")
-                (str/split-lines)
-                (split-with not-empty)
-                ((juxt
-                  (fn [lst]
-                    (reduce
-                      #(conj %1 (mapv read-string (str/split %2 #",")))
-                      #{} (first lst)))
-                  (fn [lst]
-                    (->> (second lst)
-                         (drop 1)
-                         (map #(-> %
-                                   (str/split #"=")
-                                   (update 0 (comp {\x 0 \y 1} last))
-                                   (update 1 read-string)))
-                         ))))))
-
-(defn fold-point [idx chg pt]
-  (cond-> pt (> (get pt idx) chg) (update idx #(- % (* 2 (- % chg))))))
-
-(defn print-grid [pts]
-  (let [xmax (inc (apply max (map first pts)))
-        ymax (inc (apply max (map second pts)))]
-    (doseq [y (range 0 ymax)]
-      (println
-        (str/join
-          (for [x (range 0 xmax)] (if (contains? pts [x y]) \@ \ ))
-          )))))
-
-; Part 1
-(let [instruction (first (second input))]
-  (->> (first input)
-       (map (partial fold-point (first instruction) (second instruction)))
-       (distinct)
-       (count)
-       (println)))
-
-; Part 2
-(print-grid
-  (apply
-    (partial
-      reduce
-      #(let [ins (first %2)]
-         (set (map (partial fold-point (first %2) (second %2)) %1))))
-    input
-    ))
-
diff --git a/day14/part1.clj b/day14/part1.clj
deleted file mode 100644 (file)
index de03bda..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-(require '[clojure.string :as str])
-
-(def input (->> (slurp "./in")
-                str/split-lines
-                ((juxt
-                   first
-                   (fn [lines]
-                     (->> lines
-                       (drop 2)
-                       (map #(str/split % #" -> "))
-                       (flatten)
-                       (apply (partial assoc {}))
-                       ))))))
-
-(defn grow-polymer [polymer insertion-rules]
-  (str/join
-    (cons
-      (first polymer)
-      (mapcat (juxt insertion-rules second)
-        (for [i (range 0 (dec (count polymer)))]
-          (subs polymer i (+ i 2)))))))
-
-(def growth-seq (iterate #(grow-polymer % (second input)) (first input)))
-
-(let [freqs (vals (frequencies (nth growth-seq 10)))]
-  (println (- (apply max freqs) (apply min freqs))))
-
diff --git a/day14/part2.clj b/day14/part2.clj
deleted file mode 100644 (file)
index f5de5fe..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-(require '[clojure.string :as str])
-
-(def input (->> (slurp "./in")
-                str/split-lines
-                ((juxt
-                   #(let [init-polymer (first %)]
-                      (for [i (range 0 (dec (count init-polymer)))]
-                        (subs init-polymer i (+ i 2))))
-                   (fn [lines]
-                     (->> lines
-                       (drop 2)
-                       (map #(str/split % #" -> "))
-                       (map (fn [[[a b] c]]
-                         {(str/join [a b]) (map str/join [[a c] [c b]])}))
-                       (reduce into)
-                       ))))))
-
-(def blank-map (zipmap (keys (second input)) (repeat 0)))
-
-(defn grow-polymer [polymer insertion-rules]
-  (reduce
-    #(let [[p1 p2] (insertion-rules (key %2)) v (val %2)]
-       (-> %1 (update p1 + v) (update p2 + v)))
-    blank-map
-    (filter (comp pos? val) polymer)))
-
-(def growth-seq
-  (iterate #(grow-polymer % (second input))
-           (reduce #(update %1 %2 inc) blank-map (first input))))
-
-(let [final-polymer (nth growth-seq 40) 
-      letter-counts (reduce
-                      (fn [r [k v]] (-> r (update (first k) + v) (update (second k) + v)))
-                      (zipmap (str/join (keys final-polymer)) (repeat 0))
-                      final-polymer)
-      unique-counts (filter pos? (map #(Math/ceil (/ (val %) 2)) letter-counts))]
-  (println (- (apply max unique-counts) (apply min unique-counts))))
-
diff --git a/day15/part1.clj b/day15/part1.clj
deleted file mode 100644 (file)
index 7838e34..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-(def input (->> (slurp "./in")
-                (clojure.string/split-lines)
-                (mapv (partial mapv (comp read-string str)))
-                (#(for [y (range 0 (count %)) x (range 0 (count (first %)))]
-                    {[y x] (get-in % [y x])}))
-                (into {})))
-
-(def dim (apply max (map first (keys input))))
-
-(defn find-neighbors [u]
-  (filter #(contains? input %) [(update u 0 inc)
-                                (update u 0 dec)
-                                (update u 1 inc)
-                                (update u 1 dec)]))
-
-(loop [dist (zipmap (keys input) (repeat ##Inf))
-       Q    {[0 0] 0}]
-  (if (empty? Q)
-    (println (dist [dim dim]))
-    (let [[u distu] (first Q)
-          NN (reduce
-               #(let [dv (+ distu (input %2))]
-                  (cond-> %1
-                    (> ((first %1) %2) dv)
-                    (-> (update 0 assoc %2 dv)
-                        (update 1 assoc %2 dv))))
-               [dist {}]
-               (find-neighbors u))]
-      (recur (first NN) (sort-by val < (into (rest Q) (second NN)))))))
-
diff --git a/day15/part2.clj b/day15/part2.clj
deleted file mode 100644 (file)
index a422ed0..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-(def input (->> (slurp "./in")
-                (clojure.string/split-lines)
-                (mapv (partial mapv (comp read-string str)))
-                (#(for [y (range 0 (count %)) x (range 0 (count (first %)))]
-                    {[y x] (get-in % [y x])}))
-                (into {})
-                ((fn [lst]
-                (reduce
-                  #(into %1
-                     (for [j (range 0 5) i (range 0 5)]
-                       {[(+ (first (key %2)) (* 100 j)) (+ (second (key %2)) (* 100 i))]
-                        (let [s (+ i j (val %2))] (if (> s 9) (- s 9) s))}))
-                  {}
-                  lst
-                  )))
-                (into {})
-                ))
-
-(def dim (apply max (map first (keys input))))
-
-(defn find-neighbors [u]
-  (filter #(contains? input %) [(update u 0 inc)
-                                (update u 0 dec)
-                                (update u 1 inc)
-                                (update u 1 dec)]))
-
-(loop [dist (zipmap (keys input) (repeat ##Inf))
-       Q    {[0 0] 0}]
-  (if (empty? Q)
-    (println (dist [dim dim]))
-    (let [[u distu] (first Q)
-          NN (reduce
-               #(let [dv (+ distu (input %2))]
-                  (cond-> %1
-                    (> ((first %1) %2) dv)
-                    (-> (update 0 assoc %2 dv)
-                        (update 1 assoc %2 dv))))
-               [dist {}]
-               (find-neighbors u))]
-      (recur (first NN) (sort-by val < (into (rest Q) (second NN)))))))
-
diff --git a/day16/part1.clj b/day16/part1.clj
deleted file mode 100644 (file)
index 2358e59..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-(require '[clojure.string :as str])
-(require '[clojure.set :as set])
-
-(def hex-lookup
-  {\0 "0000" \1 "0001" \2 "0010" \3 "0011"
-   \4 "0100" \5 "0101" \6 "0110" \7 "0111"
-   \8 "1000" \9 "1001" \A "1010" \B "1011"
-   \C "1100" \D "1101" \E "1110" \F "1111"})
-
-(defn binary-to-num [binstr]
-  (reduce
-    #(cond-> %1 true (* 2) (= \1 %2) inc)
-    0
-    binstr))
-
-(defn take-packet-version [packet]
-  (-> (split-at 3 packet)
-      (update 0 binary-to-num)))
-
-(defn take-literal-value [packet]
-  (let [[tid data] (split-at 3 packet)]
-    (when (= '(\1 \0 \0) tid)
-      (let [sd   (into [] data)
-            spl  (split-with #(= \1 (first %)) (partition 5 sd))
-            nums (map rest (concat (first spl) (take 1 (second spl))))]
-        [(binary-to-num (reduce concat nums))
-         (drop (* 5 (inc (count (first spl)))) sd)]
-        ))))
-
-(defn take-operator [packet]
-  (let [id (first packet) ps (str/join (rest packet))]
-    (if (= \0 id)
-      (let [bits (binary-to-num (subs ps 0 15))]
-        [(subs ps 15) bits :bits])
-      (let [pkts (binary-to-num (subs ps 0 11))]
-        [(subs ps 11) pkts :pkts]))))
-
-(defn process-packet [[input vcnt]]
-  (let [[version data] (take-packet-version input)]
-    (if (every? #(= \0 %) data)
-      ['() vcnt]
-      (do
-        (if-let [value (take-literal-value data)]
-          [(second value) (+ vcnt version)]
-          (do
-            (let [info (take-operator (drop 3 data))]
-              (if (= :bits (get info 2))
-                (loop [inpt [(subs (first info) 0 (get info 1)) (+ vcnt version)]]
-                  (if (empty? (first inpt))
-                    [(subs (first info) (get info 1)) (second inpt)]
-                    (recur (process-packet inpt))))
-                (loop [n (get info 1) inpt [(get info 0) (+ vcnt version)]]
-                  (if (pos? n)
-                    (recur (dec n) (process-packet inpt))
-                    inpt))))))))))
-
-(loop [packet (->> (slurp "./in")
-                   (map hex-lookup)
-                   (take-while some?)
-                   (reduce concat)
-                   (str/join)
-                   (#(vector % 0))
-                   (process-packet))]
-  (if (not (empty? (first packet)))
-    (recur (process-packet packet))
-    (println (second packet))))
-
diff --git a/day16/part2.cpp b/day16/part2.cpp
deleted file mode 100644 (file)
index 5a02df9..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-#include <algorithm>
-#include <cstdint>
-#include <iostream>
-#include <list>
-#include <map>
-#include <string>
-#include <string_view>
-#include <tuple>
-
-static const std::map<char, const char *> hexToBin = {
-    {'0', "0000"}, {'1', "0001"}, {'2', "0010"}, {'3', "0011"},
-    {'4', "0100"}, {'5', "0101"}, {'6', "0110"}, {'7', "0111"},
-    {'8', "1000"}, {'9', "1001"}, {'A', "1010"}, {'B', "1011"},
-    {'C', "1100"}, {'D', "1101"}, {'E', "1110"}, {'F', "1111"}
-};
-
-static std::pair<uint64_t, std::string_view> solve(std::string_view packet);
-
-int main(int argc, const char *argv[])
-{
-    if (argc != 2)
-        return -1;
-
-    std::string packetBin;
-    std::string packetHex (argv[1]);
-    for (char c : packetHex)
-        packetBin += hexToBin.at(c);
-
-    std::cout << solve(packetBin).first << std::endl;
-
-    return 0;
-}
-
-uint64_t binStrToInt(std::string_view bin)
-{
-    uint64_t n = 0;
-
-    for (char c : bin) {
-        n = n * 2ull;
-        if (c == '1')
-            ++n;
-    }
-
-    return n;
-}
-
-bool isEmptyPacket(std::string_view packet)
-{
-    return packet.empty() ||
-           std::all_of(packet.cbegin(), packet.cend(),
-                       [](char c) { return c == '0'; });
-}
-
-std::pair<uint64_t, std::string_view> solve(std::string_view packet)
-{
-    // Remove version
-    packet = packet.substr(3);
-    // Pull type ID
-    const auto typeId = packet.substr(0, 3);
-    packet = packet.substr(3);
-    
-    if (typeId == "100") {
-        std::string numberStr;
-        while (1) {
-            const auto chunk = packet.substr(0, 5);
-            packet = packet.substr(5);
-            numberStr += chunk.substr(1);
-            if (chunk.front() == '0')
-                break;
-        }
-
-        return {binStrToInt(numberStr), isEmptyPacket(packet) ? "" : packet};
-    } else {
-        const bool isLengthBits = packet.front() == '0';
-        packet = packet.substr(1);
-        const auto lengthStr = packet.substr(0, isLengthBits ? 15 : 11);
-        const auto length = binStrToInt(lengthStr);
-        packet = packet.substr(isLengthBits ? 15 : 11);
-
-        std::list<uint64_t> args;
-        if (isLengthBits) {
-            auto rem = packet.substr(0, length);
-            while (1) {
-                const auto ret = solve(rem);
-                args.emplace_front(ret.first);
-                if (ret.second.empty() || isEmptyPacket(ret.second))
-                    break;
-                rem = ret.second;
-            }
-            packet = packet.substr(length);
-        } else {
-            for (uint64_t i = 0; i < length; ++i) {
-                const auto ret = solve(packet);
-                args.emplace_front(ret.first);
-                packet = ret.second;
-                if (isEmptyPacket(packet))
-                    break;
-            }
-        }
-
-        uint64_t result;
-        if (typeId == "000") {
-            result = 0;
-            for (auto a : args)
-                result += a;
-        } else if (typeId == "001") {
-            result = 1;
-            for (auto a : args)
-                result *= a;
-        } else if (typeId == "010") {
-            result = *std::min_element(args.cbegin(), args.cend());
-        } else if (typeId == "011") {
-            result = *std::max_element(args.cbegin(), args.cend());
-        } else if (typeId == "101") {
-            const auto a1 = args.back();
-            args.pop_back();
-            result = args.back() < a1;
-        } else if (typeId == "110") {
-            const auto a1 = args.back();
-            args.pop_back();
-            result = args.back() > a1;
-        } else if (typeId == "111") {
-            const auto a1 = args.back();
-            args.pop_back();
-            result = args.back() == a1;
-        }
-
-        return {result, isEmptyPacket(packet) ? "" : packet};
-    }
-}
-
diff --git a/day17/part3.clj b/day17/part3.clj
deleted file mode 100644 (file)
index ae51260..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-;
-;
-; Put into a lein project so that you can pass Java more RAM (e.g. -Xmx15G)
-; https://www.reddit.com/r/adventofcode/comments/riqtwx/2021_day_17_day_17_part_3/
-;
-;
-
-(require '[clojure.core.reducers :as r])
-
-(def target-area [[20000 -5000] [30000 -10000]])
-(def initial-pos [0 0])
-
-(defn beyond-target? [[[tbx tby] [tex tey]] [x y]]
-  (or (> x tex) (< y tey)))
-
-(defn within-target? [[[tbx tby] [tex tey]] [x y]]
-  (and (>= x tbx) (<= x tex) (<= y tby) (>= y tey)))
-
-(defn apply-velocity [[[px py] [vx vy]]]
-  [[(+ px vx) (+ py vy)] [(cond-> vx (pos? vx) dec) (dec vy)]])
-
-(defn take-last-while [pred coll]
-  (loop [v (first coll) r (rest coll)]
-    (if (not (pred (first r)))
-      v
-      (recur (first r) (rest r)))))
-
-(defn build-path [target vel]
-  (->> (iterate apply-velocity [initial-pos vel])
-       (take-last-while (comp not (partial beyond-target? target) first))
-       (first)))
-
-; Used to determine best x velocity for highest path
-(def tnum-seq (iterate #(do [(apply + %) (inc (second %))]) [0 1]))
-
-(let [[tb te]      target-area
-      lowest-x     (second (last (take-while #(< (first %) (first tb)) tnum-seq)))
-      highest-y    (dec (Math/abs (second te)))]
-  (->> (for [y (range (second te) (inc highest-y))
-             x (range lowest-x (inc (first te)))] [x y])
-       (#(do (println "Generated xy pairs...") %))
-       (#(do (println "Total: " (* (- highest-y (second te)) (- (inc highest-y) lowest-x))) %))
-       (partition 1000000)
-       (#(do (println "Prepared partitions...") %))
-       (reduce
-          (fn [sum nlst]
-            (println sum)
-            (+ sum
-              (r/fold +
-                (r/monoid
-                  (fn [tot xy]
-                    (cond-> tot
-                      (within-target? target-area (build-path target-area xy))
-                      inc))
-                  (constantly 0))
-                (into [] nlst))))
-           0)
-       (println)))
-
diff --git a/day17/partboth.clj b/day17/partboth.clj
deleted file mode 100644 (file)
index c585bf9..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-(require '[clojure.core.reducers :as r])
-
-;(def target-area [[169 -68] [206 -108]])
-(def target-area [[20000 -5000] [30000 -10000]])
-;(def target-area [[2000 -500] [3000 -1000]])
-(def initial-pos [0 0])
-
-(defn beyond-target? [[[tbx tby] [tex tey]] [x y]]
-  (or (> x tex) (< y tey)))
-
-(defn within-target? [[[tbx tby] [tex tey]] [x y]]
-  (and (>= x tbx) (<= x tex) (<= y tby) (>= y tey)))
-
-(defn apply-velocity [[[px py] [vx vy]]]
-  [[(+ px vx) (+ py vy)] [(cond-> vx (pos? vx) dec) (dec vy)]])
-
-(defn take-last-while [pred coll]
-  (loop [v (first coll) r (rest coll)]
-    (if (not (pred (first r)))
-      v
-      (recur (first r) (rest r)))))
-
-(defn build-path [target vel]
-  (->> (iterate apply-velocity [initial-pos vel])
-       (take-last-while (comp not (partial beyond-target? target) first))
-       (first)))
-
-; Used to determine best x velocity for highest path
-(def tnum-seq (iterate #(do [(apply + %) (inc (second %))]) [0 1]))
-
-(let [[tb te]      target-area
-      lowest-x     (second (last (take-while #(< (first %) (first tb)) tnum-seq)))
-      highest-y    (dec (Math/abs (second te)))]
-  (->> (for [y (range (second te) (inc highest-y))
-             x (range lowest-x (inc (first te)))] [x y])
-       (#(do (println "Generated xy pairs...") %))
-       (#(do (println "Total: " (* (- highest-y (second te)) (- (inc highest-y) lowest-x))) %))
-       (partition 50000)
-       (#(do (println "Prepared partitions...") %))
-       (reduce
-          (fn [sum nlst]
-            (println sum)
-            (+ sum
-              (r/fold +
-                (r/monoid
-                  (fn [tot xy]
-                    (cond-> tot
-                      (within-target? target-area (build-path target-area xy))
-                      inc))
-                  (constantly 0))
-                (into [] nlst))))
-           0)
-       (println)))
-
diff --git a/day18/partboth.clj b/day18/partboth.clj
deleted file mode 100644 (file)
index 83fc42c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-(require '[clojure.core.reducers :as r])
-(require '[clojure.set :as set])
-(require '[clojure.zip :as z])
-
-(defn zip-depth [loc]
-  (loop [l loc d 0] (if (nil? l) d (recur (z/up l) (inc d)))))
-
-(defn zip-prev-num [loc]
-  (loop [l loc]
-    (if-let [prev (z/prev l)]
-      (if (not (z/branch? prev))
-        prev
-        (recur prev)))))
-
-(defn zip-next-num [loc]
-  (loop [l loc]
-    (if-let [nxt (z/next l)]
-      (if (not (z/branch? nxt))
-        (when (some? (z/node nxt)) nxt)
-        (recur nxt)))))
-
-(defn snailfish-explode [tree]
-  (loop [node (z/vector-zip tree)]
-    (if (z/end? node)
-      node
-      (if (and (z/branch? node)
-               (= 2 (count (z/children node)))
-               (and (not (z/branch? (z/down node))) (not (z/branch? (z/next (z/down node)))))
-               (> (zip-depth node) 5))
-        (let [children (z/children node)
-              nnode    (z/replace node 0)]
-          (if-let [prev (zip-prev-num nnode)]
-            (z/root
-              (let [new-prev (z/edit prev + (first children))]
-                (if-let [nxt (nth (iterate zip-next-num new-prev) 2)]
-                  (z/edit nxt + (second children))
-                  new-prev)))
-            (when-let [nxt (zip-next-num nnode)]
-              (z/root (z/edit nxt + (second children))))))
-        (recur (z/next node))))))
-
-(defn snailfish-split [tree]
-  (loop [node (z/vector-zip tree)]
-    (if (or (z/end? node) (nil? (z/node node)))
-      node
-      (if (and (not (z/branch? node)) (> (z/node node) 9))
-        (z/root
-          (z/replace node
-            (z/make-node node (z/node node)
-              (map long [(Math/floor (/ (z/node node) 2))
-                         (Math/ceil (/ (z/node node) 2))]))))
-        (recur (z/next node))))))
-
-(defn snailfish-magnitude [ntree]
-    (if (= 2 (count (z/children ntree)))
-      (let [cl (z/down ntree) cr (z/right cl)]
-        (+ (* 3 (if (z/branch? cl) (snailfish-magnitude cl) (z/node cl)))
-           (* 2 (if (z/branch? cr) (snailfish-magnitude cr) (z/node cr)))))
-      (loop [node (z/down ntree) sum 0]
-        (if (nil? node)
-          sum
-          (recur (z/right node)
-                 (+ sum (if (z/branch? node) (snailfish-magnitude node) (z/node node))))))))
-
-(defn snailfish-solve [add-list]
-  (snailfish-magnitude
-    (loop [result     (z/vector-zip (vec (take 2 add-list)))
-           next-input (drop 2 add-list)]
-      (let [explode (snailfish-explode result)]
-        (if (nil? (second explode))
-          (recur explode next-input)
-          (let [splt (snailfish-split result)]
-            (if (nil? (second splt))
-              (recur splt next-input)
-              (if (empty? next-input)
-                result
-                (recur (z/vector-zip
-                         [(vec (z/children result)) (first next-input)])
-                       (rest next-input))))))))))
-
-; Build input list
-(def input (->> (slurp "./in")
-                clojure.string/split-lines
-                (map read-string)))
-
-; Part 1
-(println (snailfish-solve input))
-
-; Part 2
-(->> (for [in input in2 input :when (not= in in2)] [in in2])
-     (vec)
-     (r/map snailfish-solve)
-     (r/fold (r/monoid max (constantly 0)))
-     (println))
-
diff --git a/day19/partboth.clj b/day19/partboth.clj
deleted file mode 100644 (file)
index 48f1a9c..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-(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)))))))
-
diff --git a/day2/part1.clj b/day2/part1.clj
deleted file mode 100644 (file)
index e4e9d49..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-; Day 2, part 1
-; Read a list of instructions from stdin:
-;   "down X" increases depth number by X,
-;   "up X" decreases depth by X,
-;   "forward X" increases xpos by X.
-; Print (xpos * depth) after end of data.
-;
-
-(require '[clojure.string :as str])
-
-(println
-  (reduce *
-    (vals
-      (reduce
-        #(case (first %2)
-           "forward" (update %1 :xpos  + (second %2))
-           "up"      (update %1 :depth - (second %2))
-           "down"    (update %1 :depth + (second %2))
-           )
-        {:xpos 0 :depth 0}
-        (->> (slurp "./in")
-             str/split-lines
-             (map #(str/split % #" "))
-             (map #(update % 1 read-string))
-             )))))
-
diff --git a/day2/part2.clj b/day2/part2.clj
deleted file mode 100644 (file)
index 9487a49..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-; Day 2, part 2
-; Read a list of instructions from stdin:
-;   "down X" increases aim number by X,
-;   "up X" decreases aim by X,
-;   "forward X" increases xpos by X and depth by (aim * X).
-; Print (xpos * depth) after end of data.
-;
-
-(require '[clojure.string :as str])
-
-(println
-  (apply *
-    (map
-      (reduce
-        #(case (first %2)
-           "forward" (-> %1 (update :xpos + (second %2))
-                            (update :depth + (* (%1 :aim) (second %2))))
-           "up"      (update %1 :aim - (second %2))
-           "down"    (update %1 :aim + (second %2)))
-        {:xpos 0 :depth 0 :aim 0}
-        (->> (slurp "./in")
-             str/split-lines
-             (map #(str/split % #" "))
-             (map #(update % 1 read-string))))
-      [:xpos :depth]
-      )))
-
diff --git a/day20/partboth.clj b/day20/partboth.clj
deleted file mode 100644 (file)
index 33a4d4f..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-(require '[clojure.string :as str])
-
-(defn pad-input-map [in-map pad-val]
-  (let [ly (count in-map) lx (count (first in-map))
-        sy (+ 4 ly) sx (+ 4 lx)
-        buffer (byte-array (repeat (* sy sx) pad-val))]
-    (doseq [y (range 0 ly) x (range 0 lx)]
-      (aset-byte buffer (+ (* sx (+ 2 y)) 2 x) (get-in in-map [y x])))
-    (mapv vec (partition sx buffer))))
-
-(defn get-number [in-map y x]
-  (map (partial get-in in-map)
-       [[(dec y) (dec x)] [(dec y) x] [(dec y) (inc x)]
-        [y (dec x)]       [y x]       [y (inc x)]
-        [(inc y) (dec x)] [(inc y) x] [(inc y) (inc x)]]))
-
-(defn get-new-pixel [enhance-algo in-map y x]
-  (->> (get-number in-map y x)
-       (reduce #(cond-> (* 2 %1) (= 1 %2) inc) 0)
-       (get enhance-algo)))
-
-(defn build-output-number-map [enhance-algo in-map]
-  (let [pad-val (if (pos? (first enhance-algo)) (first (first in-map)) 0)
-        padded-in-map (pad-input-map in-map pad-val)]
-    (->> (for [y (range 1 (dec (count padded-in-map)))]
-           (future
-             (mapv (partial get-new-pixel enhance-algo padded-in-map y)
-                   (range 1 (dec (count (first padded-in-map)))))))
-         (mapv deref))))
-
-(defn count-lit-pixels [in-map] ((frequencies (flatten in-map)) 1))
-
-(let [[enhance-algo in-map]
-      (->> (slurp "./in")
-           str/split-lines
-           ((juxt (comp (partial mapv {\. 0 \# 1}) first)
-                  (comp (partial mapv #(mapv {\. 0 \# 1} %)) (partial drop 2)))))
-      image-output (iterate (partial build-output-number-map enhance-algo) in-map)]
-  (println "Part 1:" (count-lit-pixels (nth image-output 2)))
-  (println "Part 2:" (count-lit-pixels (nth image-output 50))))
-
-(shutdown-agents)
-
diff --git a/day21/part1.clj b/day21/part1.clj
deleted file mode 100644 (file)
index 174f5a1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-(require 'clojure.string)
-
-(loop [player-positions   (->> (slurp "./in")
-                               clojure.string/split-lines
-                               (map (comp read-string second #(clojure.string/split % #": ")))
-                               (mapv #(drop (dec %) (cycle (range 1 11)))))
-       player-scores      (into [] (repeat (count player-positions) 0))
-       player-turn        (cycle (range 0 (count player-scores)))
-       deterministic-dice (cycle (range 1 101))
-       dice-roll-count    0]
-  (if-not (every? #(< % 1000) player-scores)
-    (println (* dice-roll-count (apply min player-scores)))
-    (let [roll         (reduce + (take 3 deterministic-dice))
-          turn         (first player-turn)
-          new-position (drop roll (get player-positions turn))]
-      (recur
-        (assoc player-positions turn new-position)
-        (update player-scores turn + (first new-position))
-        (next player-turn)
-        (drop 3 deterministic-dice)
-        (+ dice-roll-count 3)))))
-
diff --git a/day21/part2.clj b/day21/part2.clj
deleted file mode 100644 (file)
index 0042aaa..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-(defn dice-probability-spread [sides rolls]
-  (let [sr (range 1 (inc sides))]
-    (->> sr
-         (iterate #(flatten (for [i sr] (map (partial + i) %))))
-         (drop (dec rolls))
-         ((comp frequencies first)))))
-
-(def rolls (dice-probability-spread 3 3))
-
-(defn advance-pos [pos roll] (let [n (+ pos roll)] (if (> n 10) (- n 10) n)))
-
-(defn add-roll [state roll p1-turn]
-  (let [pos   (if p1-turn :pos1 :pos2)
-        score (if p1-turn :score1 :score2)
-        new-pos (advance-pos (state pos) roll)]
-    (-> state
-        (assoc pos new-pos)
-        (update score + new-pos))))
-
-(defonce wins (atom [0 0]))
-
-(loop [turn 0 states {{:pos1 4 :score1 0 :pos2 8 :score2 0} 1}]
-  (if (empty? states)
-    (println (apply max @wins))
-    (recur
-      (if (= 0 turn) 1 0)
-      (reduce
-        #(let [kvp (first %2)]
-           (if (< ((key kvp) (if (= 0 turn) :score1 :score2)) 21)
-             (if (contains? %1 (key kvp))
-               (update %1 (key kvp) +' (val kvp))
-               (conj %1 kvp))
-             (do (swap! wins update turn +' (val kvp)) %1)))
-        {}
-        (for [s states r rolls]
-          {(add-roll (first s) (key r) (= 0 turn)) (*' (second s) (val r))})))))
-
diff --git a/day22/part1.clj b/day22/part1.clj
deleted file mode 100644 (file)
index bffc1a9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-(require '[clojure.string :as str])
-
-(def input (->> (slurp "./in")
-                (str/split-lines)
-                (map
-                  (fn [line]
-                    [(if (str/starts-with? line "on") true false)
-                     (->> (str/split line #"[^-\d]+")
-                          (rest)
-                          (map #(Integer/parseInt %))
-                          (partition 2))]))))
-
-(println
-  (frequencies
-    (vals
-      (reduce
-        (fn [cmap c]
-          (into cmap
-            (let [[xx yy zz] (second c)]
-              (for [x (range (max -50 (first xx)) (inc (min 50 (second xx))))
-                    y (range (max -50 (first yy)) (inc (min 50 (second yy))))
-                    z (range (max -50 (first zz)) (inc (min 50 (second zz))))]
-                [[x y z] (first c)]))))
-        {} input))))
-
diff --git a/day22/part2.clj b/day22/part2.clj
deleted file mode 100644 (file)
index c5d2803..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-(require '[clojure.core.reducers :as r])
-(require '[clojure.string :as str])
-
-(def input (->> (slurp "./in")
-                (str/split-lines)
-                (map
-                  (fn [line]
-                    [(if (str/starts-with? line "on") true false)
-                     (->> (str/split line #"[^-\d]+")
-                          (rest)
-                          (map #(Integer/parseInt %))
-                          (partition 2)
-                          (mapv vec))]))
-                (reverse)))
-
-(defn build-coord-list [coords idx]
-  (->> coords
-       (map #(update (get (second %) idx) 1 inc))
-       (flatten)
-       (sort)
-       (vec)))
-
-(defn filter-coord-list [coords idx v]
-  (filter
-    #(let [[p0 p1] (get (second %) idx)]
-       (and (<= p0 v) (<= v p1)))
-    coords))
-
-(def xs (build-coord-list input 0))
-(def ys (build-coord-list input 1))
-(def zs (build-coord-list input 2)) 
-
-(defonce on-count (atom 0))
-
-(loop [x xs]
-  (when-not (empty? (rest x))
-    (println "x=" (first x))
-    (let [inputx (filter-coord-list input 0 (first x))]
-      (swap! on-count +
-        (r/fold
-          32
-          +
-          (fn [onc2 iy]
-            (let [inputy (filter-coord-list inputx 1 (get ys iy))]
-              (+ onc2
-                (reduce
-                  (fn [onc iz]
-                    (let [inputz (first (filter-coord-list inputy 2 (get zs iz)))]
-                      (cond-> onc
-                        (first inputz)
-                        (+ (* (- (second x) (first x))
-                              (- (get ys (inc iy)) (get ys iy))
-                              (- (get zs (inc iz)) (get zs iz)))))))
-                  0
-                  (range 0 (dec (count zs)))))))
-          (into [] (range 0 (dec (count ys))))))
-      (recur (rest x)))))
-
-(println @on-count)
-
diff --git a/day23/part1-done-by-hand b/day23/part1-done-by-hand
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/day23/part2.clj b/day23/part2.clj
deleted file mode 100644 (file)
index adbefc1..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-(require '[clojure.core.reducers :as r])
-
-(def init-field
-  [nil
-   nil
-   (seq [:b :d :d :d])
-   nil
-   (seq [:b :c :b :a])
-   nil
-   (seq [:c :b :a :a])
-   nil
-   (seq [:d :a :c :c])
-   nil
-   nil])
-
-(defn do-slot [[field energy] idx]
-  (let [slot (get field idx)]
-    (cond
-      ; Moving value out of a room
-      (and (seq? slot)
-           (not (empty? slot))
-           (not (every? #(= % ({2 :a 4 :b 6 :c 8 :d} idx)) slot)))
-      (let [open-slots
-            (filterv
-              #(contains? #{0 1 3 5 7 9 10} %)
-              (concat
-                (for [i (reverse (range 0 idx))
-                      :while (or (nil? (get field i)) (seq? (get field i)))] i)
-                (for [i (range idx (count field))
-                      :while (or (nil? (get field i)) (seq? (get field i)))] i)))]
-        (when-not (empty? open-slots)
-          (map
-            (fn [os]
-              [(-> field
-                   (assoc os (first slot))
-                   (update idx rest))
-               (+ energy (* ({:a 1 :b 10 :c 100 :d 1000} (first slot))
-                            (+ (inc (- 4 (count slot))) (Math/abs (- os idx)))))])
-            open-slots)))
-      ; Moving value into a room
-      (and (not (seq? slot)) (some? slot))
-      (let [our-room ({:a 2 :b 4 :c 6 :d 8} slot)]
-        (if (every? #(or (nil? (get field %)) (seq? (get field %)))
-                    (range (inc (min our-room idx)) (max our-room idx)))
-          (let [room (get field our-room)]
-            (when (or (empty? room) (every? #(= slot %) room))
-              [(-> field
-                   (assoc idx nil)
-                   (update our-room conj slot))
-               (+ energy (* ({:a 1 :b 10 :c 100 :d 1000} slot)
-                            (+ (Math/abs (- idx our-room)) (- 4 (count room)))))])))))))
-
-(defn winner? [[field q s]]
-  (= field
-    [nil
-     nil
-     (seq [:a :a :a :a])
-     nil
-     (seq [:b :b :b :b])
-     nil
-     (seq [:c :c :c :c])
-     nil
-     (seq [:d :d :d :d])
-     nil
-     nil]))
-
-(defn do-turns [fields]
-  (into #{}
-    (r/fold
-      r/cat
-      #(if-let [t (apply do-slot %2)]
-         (if (seq? t)
-           (reduce r/append! %1 t)
-           (r/append! %1 t))
-         %1)
-      (into [] (for [f fields i (range 0 11)] [f i])))))
-
-(defn play-games [turns tc]
-  (println "Games:" (count turns) "Turn:" tc)
-  (let [new-turns (do-turns turns)
-        winners (filter winner? new-turns)]
-    (if (seq winners)
-      (map second winners)
-      (recur new-turns (inc tc)))))
-
-(->> (play-games #{[init-field 0]} 0)
-     sort
-     first
-     ((partial println "Lowest energy:")))
-
diff --git a/day24/checker.clj b/day24/checker.clj
deleted file mode 100644 (file)
index 4874f62..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-(require '[clojure.string :as str])
-
-(defn alu-parse-argument [arg]
-  (if (contains? #{\w \x \y \z} (first arg))
-    (str/join ["@" arg])
-    (read-string arg)))
-
-(defn alu-parse-instruction [[ins arg1 arg2]]
-  (let [arg2-parsed (if (some? arg2) (alu-parse-argument arg2) 0)]
-    (case ins
-      "inp"
-      (str/join ["(reset! " arg1 " (- (int (get input (swap! index inc))) 48))\n"])
-      "add"
-      (str/join ["(swap! " arg1 " +' " arg2-parsed ")\n"])
-      "mul"
-      (str/join ["(swap! " arg1 " *' " arg2-parsed ")\n"])
-      "div"
-      (str/join ["(swap! " arg1 " quot " arg2-parsed ")\n"])
-      "mod"
-      (str/join ["(swap! " arg1 " rem " arg2-parsed ")\n"])
-      "eql"
-      (str/join ["(swap! " arg1 " #(if (= % " arg2-parsed ") 1 0))\n"]))))
-
-(def alu-program-header
-    "(defn alu-program [input]
-     (let [index (atom -1) w (atom 0) x (atom 0) y (atom 0) z (atom 0)]\n")
-
-(defn alu-compile-program [instructions]
-  (let [parsed-ins (mapv alu-parse-instruction instructions)]
-    (eval (read-string
-      (str/join [alu-program-header
-                 (str/join parsed-ins)
-                 "@z))"])))))
-
-(def program (->> (slurp "./in")
-                  str/split-lines
-                  (map #(str/split % #"\s+"))
-                  (alu-compile-program)))
-
-; to split by `inp w`s:
-;                  (partition 18)
-;                  (reverse)
-;                  (mapv alu-compile-program)))
-
-(println "Part 1:" (program "16181111641521"))
-(println "Part 2:" (program "59692994994998"))
-
diff --git a/day24/partboth.clj b/day24/partboth.clj
deleted file mode 100644 (file)
index 9548ec3..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-(require '[clojure.string :as str])
-
-; The given program operates on a base-26 stack, either pushing or
-; (conditionally) popping values. This code extracts those operations
-; from the input, then works through them to determine the highest
-; and lowest values that produce an output of zero.
-; See the .md file in this directory for more info.
-
-(def program (->> (slurp "./in")
-                  str/split-lines
-                  (map #(str/split % #"\s+"))
-                  (partition 18)
-                  (map (fn [step]
-                    (if (= "1" (last (nth step 4)))
-                      [:push (read-string (last (nth step 15)))]
-                      [:pop (read-string (last (nth step 5)))])
-                    ))))
-
-(defn program-index [prog] (- 14 (count prog)))
-
-(loop [numbers (vec (repeat 2 (vec (repeat 14 0))))
-       stack '()
-       prog program]
-  (if-let [step (first prog)]
-    (if (= :push (first step))
-      (recur numbers
-             (conj stack [(program-index prog) (second step)])
-             (rest prog))
-      (let [i2     (program-index prog)
-            [i1 v] (first stack)
-            diff   (+ v (second step))]
-        (recur
-          [(if (neg? diff)
-             (-> (first numbers) (assoc i1 9) (assoc i2 (+ 9 diff)))
-             (-> (first numbers) (assoc i2 9) (assoc i1 (- 9 diff))))
-           (if (neg? diff)
-             (-> (second numbers) (assoc i2 1) (assoc i1 (- 1 diff)))
-             (-> (second numbers) (assoc i1 1) (assoc i2 (+ 1 diff))))]
-          (rest stack) (rest prog))))
-  (println (map str/join numbers))))
-
diff --git a/day24/solved-by-hand-with-help.md b/day24/solved-by-hand-with-help.md
deleted file mode 100644 (file)
index 1ddf03e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Went through this wonderful guide:
-
-[https://github.com/mrphlip/aoc/blob/master/2021/24.md](https://github.com/mrphlip/aoc/blob/master/2021/24.md)
-
diff --git a/day25/part1.clj b/day25/part1.clj
deleted file mode 100644 (file)
index df2947c..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-(require '[clojure.string :as str])
-
-(defn cucumber-step-east [cuc-map]
-  (for [cuc-row cuc-map]
-    (let [shifted-cuc (str/replace cuc-row #">\." ".>")]
-      (if (and (= \> (last cuc-row)) (= \. (first cuc-row)))
-        (-> shifted-cuc
-            (str/replace #">$" ".")
-            (str/replace #"^\." ">"))
-        shifted-cuc))))
-
-(defn cucumber-step-south [cuc-map]
-  (let [extra-cuc-map
-        (conj (vec (cons (last cuc-map) cuc-map)) (first cuc-map))
-        new-extra-cuc-map
-        (for [y (reverse (range 1 (count extra-cuc-map)))]
-          (str/join
-            (for [x (range 0 (count (first cuc-map)))]
-              (cond
-                (and (= \. (get-in extra-cuc-map [y x])) (= \v (get-in extra-cuc-map [(dec y) x])))
-                \v
-                (and (= \v (get-in extra-cuc-map [y x])) (= \. (get-in extra-cuc-map [(inc y) x])))
-                \.
-                :else
-                (get-in extra-cuc-map [y x])))))]
-    (into [] (reverse (rest new-extra-cuc-map)))))
-
-(defn cucumber-seq [cuc-map-init]
-  (iterate (comp cucumber-step-south cucumber-step-east) cuc-map-init))
-
-(def input (->> (slurp "./in")
-                (str/split-lines)
-                (vec)))
-
-(loop [cuc-hist '() cuc-list (cucumber-seq input)]
-  (let [next-cuc (first cuc-list)]
-    (if (or (nil? next-cuc) (= (first cuc-hist) next-cuc))
-      (println "Cucs are stuck! Steps:" (count cuc-hist))
-      (recur (conj cuc-hist next-cuc) (rest cuc-list)))))
-
diff --git a/day3/part1.clj b/day3/part1.clj
deleted file mode 100644 (file)
index 3fe888e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-(require '[clojure.string :as str])
-
-(->> "./in"
-     (slurp)
-     (str/split-lines)
-     (map (fn [l] (map #(if (= % \1) 1 0) l)))
-     (apply (partial map +))
-     (map #(if (< % 500) \1 \0))
-     (str/join)
-     (#(Integer/parseInt % 2))
-     (#(* % (bit-xor % (dec (int (Math/pow 2 12))))))
-     (println)
-     )
-
-; (->> input data file name
-;      read in entire contents
-;      split contents into array of lines
-;      for each line, transform characters '1'/'0' to numbers
-;      build sum array using the lines
-;      convert back to array of characters
-;      join characters into single string
-;      convert binary string to a number (gamma)
-;      multiply gamma by its bit-inverse (bit length hard-coded)
-;      print results
-
diff --git a/day3/part2.clj b/day3/part2.clj
deleted file mode 100644 (file)
index 00e656f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-(require '[clojure.string :as str])
-
-(def bitcount 12)
-(def input
-  (->> "./in"
-      (slurp)
-      (str/split-lines)
-      (map #(Integer/parseInt % 2))
-      )
-  )
-
-(defn countbit [lst bit]
-  (->> lst
-       (map #(if (bit-test % bit) 1 0))
-       (apply +)
-       )
-  )
-
-(defn filterbit [lst bit v]
-  (if (= 1 (count lst))
-    lst
-    (filter #(= (bit-test % bit) v) lst)
-    )
-  )
-
-(loop [bit (dec bitcount) lst0 input lst1 input]
-  (if (and (= 1 (count lst0)) (= 1 (count lst1)))
-    (println (map * lst0 lst1))
-    (recur
-      (dec bit)
-      (filterbit lst0 bit (>= (countbit lst0 bit) (/ (count lst0) 2)))
-      (filterbit lst1 bit (< (countbit lst1 bit) (/ (count lst1) 2)))
-      )
-    )
-  )
-
diff --git a/day4/part1.clj b/day4/part1.clj
deleted file mode 100644 (file)
index b9fcceb..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-(require '[clojure.string :as str])
-
-(def calls
-  (->> (read-line)
-       (#(str/split % #","))
-       (map #(Integer/parseInt %))
-       )
-  )
-
-(defn read-board []
-  (when (some? (read-line))
-    (mapv
-        (fn [line] (->> line
-            (str/join)
-            (str/trim)
-            (#(str/split % #"\s+"))
-            (map #(Integer/parseInt %))
-            )
-          )
-        (repeatedly 5 read-line)
-        )
-    )
-  )
-
-(defn bingo? [board]
-  (some?
-    (some
-      #(every? nil? %)
-      (concat board (apply mapv vector board))
-      )
-    )
-  )
-
-(defn bingo-mark [board n]
-  (mapv (partial replace {n nil}) board)
-  )
-
-(defn get-bingo [init-board]
-  (loop [board init-board nums calls turns 1]
-    (let [new-board (bingo-mark board (first nums))]
-      (if (bingo? new-board)
-        [new-board (first nums) turns]
-        (recur new-board (rest nums) (inc turns))
-        )
-      )
-    )
-  )
-
-(loop [best [999 0] board (read-board)]
-  (if (nil? board)
-    (println best)
-    (let [bingo (get-bingo board)]
-      (recur
-        (if (< (get bingo 2) (first best))
-          [(get bingo 2)
-           (->> (first bingo)
-                (flatten)
-                (filter some?)
-                (apply +)
-                (* (second bingo))
-                )
-           ]
-          best
-          )
-        (read-board)
-        )
-      )
-    )
-  )
-
diff --git a/day4/part2.clj b/day4/part2.clj
deleted file mode 100644 (file)
index 516e83c..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-(require '[clojure.string :as str])
-
-(def calls
-  (->> (read-line)
-       (#(str/split % #","))
-       (map #(Integer/parseInt %))
-       )
-  )
-
-(defn read-board []
-  (when (some? (read-line))
-    (mapv
-        (fn [line] (->> line
-            (str/join)
-            (str/trim)
-            (#(str/split % #"\s+"))
-            (map #(Integer/parseInt %))
-            )
-          )
-        (repeatedly 5 read-line)
-        )
-    )
-  )
-
-(defn bingo? [board]
-  (some?
-    (some
-      #(every? nil? %)
-      (concat board (apply mapv vector board))
-      )
-    )
-  )
-
-(defn bingo-mark [board n]
-  (mapv (partial replace {n nil}) board)
-  )
-
-(defn get-bingo [init-board]
-  (loop [board init-board nums calls turns 1]
-    (let [new-board (bingo-mark board (first nums))]
-      (if (bingo? new-board)
-        [new-board (first nums) turns]
-        (recur new-board (rest nums) (inc turns))
-        )
-      )
-    )
-  )
-
-(loop [best [0 0] board (read-board)]
-  (if (nil? board)
-    (println best)
-    (let [bingo (get-bingo board)]
-      (recur
-        (if (> (get bingo 2) (first best))
-          [(get bingo 2)
-           (->> (first bingo)
-                (flatten)
-                (filter some?)
-                (apply +)
-                (* (second bingo))
-                )
-           ]
-          best
-          )
-        (read-board)
-        )
-      )
-    )
-  )
-
diff --git a/day5/part1.clj b/day5/part1.clj
deleted file mode 100644 (file)
index 95d04ba..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-(require '[clojure.string :as str])
-
-(defn read-coords []
-  (let [line (read-line)]
-    (when (not (empty? line))
-      (mapv
-        #(Integer/parseInt %)
-        (str/split
-          line
-          #"[^\d]+"
-          )
-        )
-      )
-    )
-  )
-
-(defn read-all-coords []
-  (loop [cds [] c (read-coords)]
-    (if (empty? c)
-      cds
-      (recur
-        (conj cds c)
-        (read-coords)
-        )
-      )
-    )
-  )
-
-(defn mark-coord [cmap x y]
-  (update cmap y #(update % x inc))
-  )
-
-(defn mark-coords [cmap x1 y1 x2 y2]
-  (cond
-    (= y1 y2)
-    (reduce
-      #(mark-coord %1 %2 y1)
-      cmap
-      (range (min x1 x2) (inc (max x1 x2)))
-      )
-    (= x1 x2)
-    (reduce
-      #(mark-coord %1 x1 %2)
-      cmap
-      (range (min y1 y2) (inc (max y1 y2)))
-      )
-    :else
-    cmap
-    )
-  )
-
-(defn empty-map []
-  (vec
-    (repeat 1000
-      (vec (repeat 1000 0))
-      )
-    )
-  )
-
-(def finished-map
-  (reduce
-    #(apply (partial mark-coords %1) %2)
-    (empty-map)
-    (read-all-coords)
-    )
-  )
-
-(->> finished-map
-    (flatten)
-    (map dec)
-    (filter pos?)
-    (count)
-    (println)
-    )
-
diff --git a/day5/part2.clj b/day5/part2.clj
deleted file mode 100644 (file)
index d324618..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-(require '[clojure.string :as str])
-
-(defn read-coords []
-  (let [line (read-line)]
-    (when (not (empty? line))
-      (mapv
-        #(Integer/parseInt %)
-        (str/split
-          line
-          #"[^\d]+"
-          )
-        )
-      )
-    )
-  )
-
-(defn read-all-coords []
-  (loop [cds [] c (read-coords)]
-    (if (empty? c)
-      cds
-      (recur
-        (conj cds c)
-        (read-coords)
-        )
-      )
-    )
-  )
-
-(defn mark-coord [cmap x y]
-  (update
-    cmap
-    [x y]
-    #(if (nil? %) 0 (inc %))
-    )
-  )
-
-(defn mark-coords [cmap x1 y1 x2 y2]
-  (cond
-    (= y1 y2)
-    (reduce
-      #(mark-coord %1 %2 y1)
-      cmap
-      (range (min x1 x2) (inc (max x1 x2)))
-      )
-    (= x1 x2)
-    (reduce
-      #(mark-coord %1 x1 %2)
-      cmap
-      (range (min y1 y2) (inc (max y1 y2)))
-      )
-    :else
-    (let [ic (if (< x1 x2) [x1 y1] [x2 y2])
-          ec (if (> x1 x2) [x1 y1] [x2 y2])
-          dy (if (> (second ec) (second ic)) 1 -1)
-          ]
-      (loop [cm cmap c ic]
-        (if (> (first c) (first ec))
-          cm
-          (recur
-            (apply (partial mark-coord cm) c)
-            [(inc (first c)) (+ dy (second c))]
-            )
-          )
-        )
-      )
-    )
-  )
-
-(def finished-map
-  (reduce
-    #(apply (partial mark-coords %1) %2)
-    {}
-    (read-all-coords)
-    )
-  )
-
-(->> finished-map
-     (vals)
-     (filter pos?)
-     (count)
-     (println)
-     )
-
diff --git a/day6/consteval.cpp b/day6/consteval.cpp
deleted file mode 100644 (file)
index f46da89..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <algorithm>
-#include <cstdint>
-#include <numeric>
-#include <iostream>
-
-consteval auto countFish(unsigned int day)
-{
-    unsigned char input[] = {
-        //3,4,3,1,2
-#include "in"
-    };
-
-    uint64_t counts[9];
-    std::fill(counts, counts + 9, 0);
-    for (int i = 0; i < sizeof(input); ++i)
-        ++counts[input[i]];
-
-    for (int i = 0; i < day; ++i) {
-        std::rotate(counts, counts + 1, counts + 9);
-        counts[6] += counts[8];
-    }
-
-    return std::accumulate(counts, counts + 9, 0ull);
-}
-
-int main()
-{
-    std::cout << "80: " << countFish(80) << std::endl;
-    std::cout << "256: " << countFish(256) << std::endl;
-    return 0;
-}
-
diff --git a/day6/part1.clj b/day6/part1.clj
deleted file mode 100644 (file)
index 70293f7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-(require '[clojure.string :as str])
-
-(def fish-init
-  (->> (read-line)
-       (#(str/split % #","))
-       (map #(Integer/parseInt %))
-       (vec)
-       )
-  )
-
-(defn cycle-day [fish]
-  (flatten
-    (for [f (map dec fish)]
-      (if (neg? f) [6 8] f)
-      )
-    )
-  )
-
-(println (count (nth (iterate cycle-day fish-init) 80)))
-
diff --git a/day6/part2.clj b/day6/part2.clj
deleted file mode 100644 (file)
index ad6fe91..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-(require '[clojure.string :as str])
-
-(->> (read-line)
-     (#(str/split % #","))
-     (map read-string)
-     (reduce #(update %1 %2 inc) (vec (repeat 9 0)))
-     (iterate
-       #(let [nf (conj (vec (rest %)) (first %))]
-          (update nf 6 (partial + (get nf 8)))
-          )
-       )
-     (#(nth % 256))
-     (apply +)
-     (println)
-     )
-
-; ->> read input from stdin
-;     split input string by commas
-;     convert string array into number array
-;     reduce to frequency counts
-;     create iterator that returns next day's counts
-;     get 256th iteration
-;     sum all frequency counts
-;     print results
-
diff --git a/day7/maxima.mac b/day7/maxima.mac
deleted file mode 100644 (file)
index a1c2d18..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-load("descriptive")$
-load("in.mac")$ /* Should define `input` list of numbers. */
-
-calcfuel(pos, distmod) :=
-    lreduce("+", map(lambda([n], distmod(abs(pos - n))), input))$
-
-calcfuel(median(input), lambda([x],x));
-calcfuel(floor(mean(input)), lambda([x], (x*(x+1)/2)));
-calcfuel(floor(mean(input)) + 1, lambda([x], (x*(x+1)/2)));
-
diff --git a/day7/part1.clj b/day7/part1.clj
deleted file mode 100644 (file)
index f08e5b4..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-(defn median [lst]
-  (as-> (count lst) $
-    (quot $ 2)
-    (subvec (vec (sort lst)) (dec $) (inc $))
-    (if (even? (count lst)) (apply + $) (second $))
-    (quot $ 2)
-    )
-  )
-
-(as-> (slurp "./in") $ ; "16,1,2,0,4,2,7,1,2,14"
-      (clojure.string/split $ #",")
-      (mapv read-string $)
-      (map (partial - (median $)) $)
-      (map #(Math/abs %) $)
-      (apply + $)
-      (println $)
-      )
-
diff --git a/day7/part2.clj b/day7/part2.clj
deleted file mode 100644 (file)
index b96b55d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-(defn calc-fuel [lst pos]
-  (reduce #(as-> %2 $
-             (- pos $)
-             (Math/abs $)
-             (/ (* $ (inc $)) 2)
-             (+ %1 $)
-             )
-          0 lst
-          )
-  )
-
-(let [input (as-> (slurp "./in") $ ;"16,1,2,0,4,2,7,1,2,14"
-                  (clojure.string/split $ #",")
-                  (map read-string $)
-                  )
-      mean (quot (apply + input) (count input))]
-  (println (min (calc-fuel input mean)
-                (calc-fuel input (inc mean))))
-  )
-
diff --git a/day8/part1.clj b/day8/part1.clj
deleted file mode 100644 (file)
index fe06fdf..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-(require '[clojure.string :as str])
-
-(->> (str/split-lines (slurp "./in"))
-     (map
-       (fn [line]
-         (as-> line $
-           (str/split $ #" ")
-           (subvec $ 11 15)
-           (filter #(.contains [2 3 4 7] (count %)) $)
-           (count $)
-           )))
-     (apply +)
-     (println)
-     )
-
diff --git a/day8/part2.clj b/day8/part2.clj
deleted file mode 100644 (file)
index 1ee3c08..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-(require '[clojure.string :as str])
-(require '[clojure.set :as set])
-
-(defn find-match
-  "
-  Searches for digit that `has segs-left` segments remaining
-  after the segments of `dig-to-cmp` are removed from the
-  digits in `cnts` with `grp-to-cmp` segments.
-  "
-  [segs-left dig-to-cmp cnts grp-to-cmp]
-  (as-> cnts $
-    (filterv #(= (first %) grp-to-cmp) $)
-    (filterv
-      #(-> (second %)
-           (str/replace (re-pattern (str/join ["[" dig-to-cmp "]"])) "")
-           (count)
-           (= segs-left)
-           )
-      $
-      )
-    (get-in $ [0 1])
-    )
-  )
-
-(defn determine-digits [line]
-  (let [counts (mapv #(do [(count %) %]) (take 10 line))
-        mcounts (into {} counts)]
-    (as-> {} $
-        (assoc $ 1 (mcounts 2)
-                 4 (mcounts 4)
-                 7 (mcounts 3)
-                 8 (mcounts 7)
-                 )
-        (assoc $ 3 (find-match 2 ($ 7) counts 5)
-                 6 (find-match 4 ($ 7) counts 6)
-                 2 (find-match 3 ($ 4) counts 5)
-                 9 (find-match 2 ($ 4) counts 6)
-                 )
-        (assoc $ 5 (find-match 2 ($ 2) counts 5))
-        (assoc $ 0 (find-match 2 ($ 5) counts 6))
-        )
-    )
-  )
-
-(println
-  (reduce
-    (fn [sum input]
-      (let [line (as-> input $
-                   (str/split $ #" ")
-                   (mapv (comp str/join sort) $)
-                   )
-            number (subvec line 11 15)
-            decoder (set/map-invert (determine-digits line))]
-        (->> number
-             (map (comp str decoder))
-             (str/join)
-             (#(Integer/parseInt %))
-             (+ sum)
-             )
-        )
-      )
-    0
-    (str/split-lines (slurp "./in"))
-    )
-  )
-
diff --git a/day9/part1.clj b/day9/part1.clj
deleted file mode 100644 (file)
index 7bd8e23..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-(def input-map
-  (->> (slurp "./in")
-       (clojure.string/split-lines)
-       (mapv vec)
-       (mapv (partial mapv #(- (int %) 48)))
-       ))
-
-(defn get-adj [y x]
-  (map (partial get-in input-map)
-       [[(dec y) x] [(inc y) x] [y (dec x)] [y (inc x)]]))
-
-(->> (for [y (range 0 (count input-map))
-           x (range 0 (count (first input-map)))
-           :let [height (get-in input-map [y x])]
-           :when (every? #(or (nil? %) (< height %))
-                         (get-adj y x))]
-           (inc height))
-     (apply +)
-     (println)
-     )
-
diff --git a/day9/part2.clj b/day9/part2.clj
deleted file mode 100644 (file)
index 3030c4e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-(require '[clojure.set])
-
-(defn get-adj 
-  "Gets vector of coords surrounding (x, y)."
-  [y x] [[(dec y) x] [(inc y) x] [y (dec x)] [y (inc x)]])
-
-(defn basin-continues? 
-  "Determines if `b` is a continuation of the basin that includes `a`."
-  [a b] (and (some? b) (not= b 9) (> b a)))
-
-(defn basin-bottom?
-  "Determines if point `p` in `hmap` is the bottom of a basin surrounded by
-   points `adj`."
-  [hmap p adj]
-  (every?
-    #(let [q (get-in hmap %)] (or (nil? q) (< (get-in hmap p) q)))
-    adj
-    ))
-
-(defn find-basin
-  "If point `yx` in `hmap` is in a basin (determined using `adj`), return a
-   list of points in the basin that are above `yx`."
-  [hmap yx adj]
-  (let [res (filter #(basin-continues? (get-in hmap yx)
-                                       (get-in hmap %))
-                    adj)]
-    (apply (partial clojure.set/union res)
-           (map #(set (find-basin hmap % (apply get-adj %))) res)
-           )))
-
-(->> (slurp "./in")
-     (clojure.string/split-lines)
-     (mapv vec)
-     (mapv (partial mapv #(- (int %) 48)))
-     (#(for [y (range 0 (count %))
-             x (range 0 (count (first %)))
-             :let [adj (get-adj y x)]
-             :when (basin-bottom? % [y x] adj)]
-         (inc (count (find-basin % [y x] adj)))))
-     (sort >)
-     (take 3)
-     (apply *)
-     (println)
-     )
-
diff --git a/year2021/day1/part1.clj b/year2021/day1/part1.clj
new file mode 100644 (file)
index 0000000..1c2c756
--- /dev/null
@@ -0,0 +1,15 @@
+; Day 1, part 1
+; Read a list of numbers from stdin, separated by newlines.
+; Count occurances of the current number being greater than
+; the previous.
+;
+
+(as-> (slurp "./in") $
+     (clojure.string/split-lines $)
+     (map read-string $)
+     (reduce
+       #(cond-> (assoc %1 0 %2) (> %2 (first %1)) (update 1 inc))
+       [(first $) 0]
+       (rest $))
+     (println (second $)))
+
diff --git a/year2021/day1/part2.clj b/year2021/day1/part2.clj
new file mode 100644 (file)
index 0000000..e496c7d
--- /dev/null
@@ -0,0 +1,15 @@
+; Day 1, part 2
+; Read a list of numbers from stdin, separated by newlines.
+; Count occurances of the current sum being greater than
+; the previous, where a sum is that of the current number,
+; the previous number, and the next number.
+;
+
+(let [input (->> (slurp "./in")
+                 clojure.string/split-lines
+                 (mapv read-string))]
+  (println
+    (count
+      (filter #(< (get input %) (get input (+ % 3)))
+        (range 0 (- (count input) 3))))))
+
diff --git a/year2021/day10/part1.clj b/year2021/day10/part1.clj
new file mode 100644 (file)
index 0000000..60ed1e6
--- /dev/null
@@ -0,0 +1,22 @@
+(def to-closing {\{ \} \( \) \[ \] \< \>})
+(def to-score {\) 3 \] 57 \} 1197 \> 25137})
+
+(defn check-line [input]
+  (loop [in input open '()]
+    (when-let [c (first in)]
+      (if (some->> (#{\} \) \] \>} c) (not= (first open)))
+        c
+        (recur
+          (rest in)
+          (if-let [op (to-closing c)]
+            (conj open op)
+            (rest open)
+            ))))))
+
+(->> (slurp "./in")
+     (clojure.string/split-lines)
+     (map (comp to-score check-line vec))
+     (filter some?)
+     (apply +)
+     (println))
+
diff --git a/year2021/day10/part2.clj b/year2021/day10/part2.clj
new file mode 100644 (file)
index 0000000..4dfaf3b
--- /dev/null
@@ -0,0 +1,24 @@
+(def to-closing {\{ \} \( \) \[ \] \< \>})
+(def to-score {\) 1 \] 2 \} 3 \> 4})
+
+(defn check-line [input]
+  (loop [in input open '()]
+    (if-let [c (first in)]
+      (when (or (nil? (#{\} \) \] \>} c)) (= (first open) c))
+        (recur
+          (rest in)
+          (if-let [op (to-closing c)]
+            (conj open op)
+            (rest open))))
+      open
+      )))
+
+(->> (slurp "./in")
+     (clojure.string/split-lines)
+     (map (comp check-line vec))
+     (filter some?)
+     (map (partial reduce #(+ (* 5 %1) (to-score %2)) 0))
+     (sort)
+     (#(nth % (quot (count %) 2)))
+     (println))
+
diff --git a/year2021/day10/partboth.clj b/year2021/day10/partboth.clj
new file mode 100644 (file)
index 0000000..78080d9
--- /dev/null
@@ -0,0 +1,34 @@
+(def to-closing {\{ \} \( \) \[ \] \< \>})
+(def to-score {\) 3 \] 57 \} 1197 \> 25137})
+(def to-score2 {\) 1 \] 2 \} 3 \> 4})
+
+(defn check-line [input]
+  (loop [in input open '()]
+    (if-let [c (first in)]
+      (if (some->> (#{\} \) \] \>} c) (not= (first open)))
+        c
+        (recur
+          (rest in)
+          (if-let [op (to-closing c)]
+            (conj open op)
+            (rest open)
+            )))
+      open
+      )))
+
+(->> (slurp "./in")
+     (clojure.string/split-lines)
+     (map (comp check-line vec))
+     ; check-line returns first invalid character, or list of characters
+     ; necessary to close the line. Work through these through `reduce`
+     ; and build the answers for both parts:
+     (reduce
+       (fn [tots nxt]
+         (if (seq? nxt)
+           (update tots 1 #(conj % (reduce (fn [a b] (+ (* 5 a) (to-score2 b))) 0 nxt)))
+           (update tots 0 #(+ % (to-score nxt)))))
+       [0 '()])
+     ; Get part 2 answer from the list of scores:
+     (#(update % 1 (fn [ns] (nth ns (quot (count ns) 2)))))
+     (println))
+
diff --git a/year2021/day11/part1.clj b/year2021/day11/part1.clj
new file mode 100644 (file)
index 0000000..5113fd4
--- /dev/null
@@ -0,0 +1,41 @@
+(defn get-adj [in y x]
+  (filter
+    #(some? (get-in in %))
+    [[(dec y) (dec x)] [(dec y) x] [(dec y) (inc x)]
+     [y (dec x)] [y (inc x)]
+     [(inc y) (dec x)] [(inc y) x] [(inc y) (inc x)]]
+    ))
+
+(defn apply-incs [in] (mapv (partial mapv inc) in))
+
+(defn next-step [indata]
+  (loop [in (apply-incs (indata :grid)) bl (indata :blinks) y 0 x 0]
+    (cond
+      (> (get-in in [y x]) 9)
+      (do
+        (recur
+          (-> (reduce
+                (fn [i n] (update-in i n #(cond-> % (pos? %) inc)))
+                in
+                (get-adj in y x))
+              (update-in [y x] #(do % 0)))
+          (inc bl)
+          0 0))
+      (< x (dec (count (first in))))
+      (recur in bl y (inc x))
+      (< y (dec (count in)))
+      (recur in bl (inc y) 0)
+      :else
+      {:grid in :blinks bl}
+      )
+    )
+  )
+
+(->> (slurp "./in")
+     (clojure.string/split-lines)
+     (map (partial map #(- (int %) 48)))
+     (assoc {} :blinks 0 :grid)
+     (iterate next-step)
+     (#(nth % 100))
+     (#(println (% :blinks))))
+
diff --git a/year2021/day11/part2.clj b/year2021/day11/part2.clj
new file mode 100644 (file)
index 0000000..4c4663c
--- /dev/null
@@ -0,0 +1,42 @@
+(defn get-adj [in y x]
+  (filter
+    #(some? (get-in in %))
+    [[(dec y) (dec x)] [(dec y) x] [(dec y) (inc x)]
+     [y (dec x)] [y (inc x)]
+     [(inc y) (dec x)] [(inc y) x] [(inc y) (inc x)]]
+    ))
+
+(defn apply-incs [in] (mapv (partial mapv inc) in))
+
+(defn next-step [indata]
+  (loop [in (apply-incs (indata :grid)) bl (indata :blinks) y 0 x 0]
+    (cond
+      (> (get-in in [y x]) 9)
+      (do
+        (recur
+          (-> (reduce
+                (fn [i n] (update-in i n #(cond-> % (pos? %) inc)))
+                in
+                (get-adj in y x))
+              (update-in [y x] #(do % 0)))
+          (inc bl)
+          0 0))
+      (< x (dec (count (first in))))
+      (recur in bl y (inc x))
+      (< y (dec (count in)))
+      (recur in bl (inc y) 0)
+      :else
+      {:grid in :blinks bl}
+      )
+    )
+  )
+
+(->> (slurp "./in")
+     (clojure.string/split-lines)
+     (map (partial map #(- (int %) 48)))
+     (assoc {} :blinks 0 :grid)
+     (iterate next-step)
+     (take-while #(pos? (apply + (flatten (% :grid)))))
+     (count)
+     (println))
+
diff --git a/year2021/day12/part1.clj b/year2021/day12/part1.clj
new file mode 100644 (file)
index 0000000..cdd4a43
--- /dev/null
@@ -0,0 +1,27 @@
+(require '[clojure.string :as str])
+
+(def caves (->> (slurp "./in")
+           (str/split-lines)
+           (map #(str/split % #"-"))
+           (map (partial map str))
+           (#(concat % (map reverse %)))
+           ))
+
+(defn get-caves-forward [klst]
+  (map #(cons (second %) klst)
+    (filter
+      #(or (< (int (first (second %))) 96)
+           (not-any? (partial = (second %)) klst))
+      (filter #(= (first %) (first klst)) caves)
+      )))
+
+(loop [lst (get-caves-forward ["start"]) ms '()]
+  (let [nxt (->> lst
+                 (map get-caves-forward)
+                 (apply concat))
+        mtchs  (concat ms (filter #(= (first %) "end") nxt))
+        nxtlst (filter #(not= (first %) "end") nxt)]
+    (if (empty? nxtlst)
+      (println (count mtchs))
+      (recur nxtlst mtchs))))
+
diff --git a/year2021/day12/part2.clj b/year2021/day12/part2.clj
new file mode 100644 (file)
index 0000000..06b2bcd
--- /dev/null
@@ -0,0 +1,50 @@
+(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)))))
+
diff --git a/year2021/day13/part1.clj b/year2021/day13/part1.clj
new file mode 100644 (file)
index 0000000..c3f08d4
--- /dev/null
@@ -0,0 +1,30 @@
+(require '[clojure.string :as str])
+
+(def input (->> (slurp "./in")
+                (str/split-lines)
+                (split-with not-empty)
+                ((juxt
+                  (fn [lst]
+                    (reduce
+                      #(conj %1 (mapv read-string (str/split %2 #",")))
+                      #{} (first lst)))
+                  (fn [lst]
+                    (->> (second lst)
+                         (drop 1)
+                         (map #(-> %
+                                   (str/split #"=")
+                                   (update 0 (comp {\x 0 \y 1} last))
+                                   (update 1 read-string)))
+                         (first)
+                         ))))))
+
+(defn fold-point [idx chg pt]
+  (cond-> pt (> (get pt idx) chg) (update idx #(- % (* 2 (- % chg))))))
+
+(let [instruction (second input)]
+  (->> (first input)
+       (map (partial fold-point (first instruction) (second instruction)))
+       (distinct)
+       (count)
+       (println)))
+
diff --git a/year2021/day13/part2.clj b/year2021/day13/part2.clj
new file mode 100644 (file)
index 0000000..6db6555
--- /dev/null
@@ -0,0 +1,33 @@
+(require '[clojure.string :as str])
+
+(def input (->> (slurp "./in")
+                (str/split-lines)
+                (split-with not-empty)
+                ((juxt
+                  (fn [lst]
+                    (reduce
+                      #(conj %1 (mapv read-string (str/split %2 #",")))
+                      #{} (first lst)))
+                  (fn [lst]
+                    (->> (rest (second lst))
+                         (map #(-> %
+                                   (str/split #"=")
+                                   (update 0 (comp {\x 0 \y 1} last))
+                                   (update 1 read-string)))
+                         ))))))
+
+(defn print-grid [pts]
+  (doseq [p pts] (println (str/join [(first p) "," (second p)]))))
+
+(defn fold-point [idx chg pt]
+  (cond-> pt (> (get pt idx) chg) (update idx #(- % (* 2 (- % chg))))))
+
+(print-grid
+  (apply
+    (partial
+      reduce
+      #(let [ins (first %2)]
+         (set (map (partial fold-point (first %2) (second %2)) %1))))
+    input
+    ))
+
diff --git a/year2021/day13/partboth.clj b/year2021/day13/partboth.clj
new file mode 100644 (file)
index 0000000..c24980d
--- /dev/null
@@ -0,0 +1,49 @@
+(require '[clojure.string :as str])
+
+(def input (->> (slurp "./in")
+                (str/split-lines)
+                (split-with not-empty)
+                ((juxt
+                  (fn [lst]
+                    (reduce
+                      #(conj %1 (mapv read-string (str/split %2 #",")))
+                      #{} (first lst)))
+                  (fn [lst]
+                    (->> (second lst)
+                         (drop 1)
+                         (map #(-> %
+                                   (str/split #"=")
+                                   (update 0 (comp {\x 0 \y 1} last))
+                                   (update 1 read-string)))
+                         ))))))
+
+(defn fold-point [idx chg pt]
+  (cond-> pt (> (get pt idx) chg) (update idx #(- % (* 2 (- % chg))))))
+
+(defn print-grid [pts]
+  (let [xmax (inc (apply max (map first pts)))
+        ymax (inc (apply max (map second pts)))]
+    (doseq [y (range 0 ymax)]
+      (println
+        (str/join
+          (for [x (range 0 xmax)] (if (contains? pts [x y]) \@ \ ))
+          )))))
+
+; Part 1
+(let [instruction (first (second input))]
+  (->> (first input)
+       (map (partial fold-point (first instruction) (second instruction)))
+       (distinct)
+       (count)
+       (println)))
+
+; Part 2
+(print-grid
+  (apply
+    (partial
+      reduce
+      #(let [ins (first %2)]
+         (set (map (partial fold-point (first %2) (second %2)) %1))))
+    input
+    ))
+
diff --git a/year2021/day14/part1.clj b/year2021/day14/part1.clj
new file mode 100644 (file)
index 0000000..de03bda
--- /dev/null
@@ -0,0 +1,27 @@
+(require '[clojure.string :as str])
+
+(def input (->> (slurp "./in")
+                str/split-lines
+                ((juxt
+                   first
+                   (fn [lines]
+                     (->> lines
+                       (drop 2)
+                       (map #(str/split % #" -> "))
+                       (flatten)
+                       (apply (partial assoc {}))
+                       ))))))
+
+(defn grow-polymer [polymer insertion-rules]
+  (str/join
+    (cons
+      (first polymer)
+      (mapcat (juxt insertion-rules second)
+        (for [i (range 0 (dec (count polymer)))]
+          (subs polymer i (+ i 2)))))))
+
+(def growth-seq (iterate #(grow-polymer % (second input)) (first input)))
+
+(let [freqs (vals (frequencies (nth growth-seq 10)))]
+  (println (- (apply max freqs) (apply min freqs))))
+
diff --git a/year2021/day14/part2.clj b/year2021/day14/part2.clj
new file mode 100644 (file)
index 0000000..f5de5fe
--- /dev/null
@@ -0,0 +1,38 @@
+(require '[clojure.string :as str])
+
+(def input (->> (slurp "./in")
+                str/split-lines
+                ((juxt
+                   #(let [init-polymer (first %)]
+                      (for [i (range 0 (dec (count init-polymer)))]
+                        (subs init-polymer i (+ i 2))))
+                   (fn [lines]
+                     (->> lines
+                       (drop 2)
+                       (map #(str/split % #" -> "))
+                       (map (fn [[[a b] c]]
+                         {(str/join [a b]) (map str/join [[a c] [c b]])}))
+                       (reduce into)
+                       ))))))
+
+(def blank-map (zipmap (keys (second input)) (repeat 0)))
+
+(defn grow-polymer [polymer insertion-rules]
+  (reduce
+    #(let [[p1 p2] (insertion-rules (key %2)) v (val %2)]
+       (-> %1 (update p1 + v) (update p2 + v)))
+    blank-map
+    (filter (comp pos? val) polymer)))
+
+(def growth-seq
+  (iterate #(grow-polymer % (second input))
+           (reduce #(update %1 %2 inc) blank-map (first input))))
+
+(let [final-polymer (nth growth-seq 40) 
+      letter-counts (reduce
+                      (fn [r [k v]] (-> r (update (first k) + v) (update (second k) + v)))
+                      (zipmap (str/join (keys final-polymer)) (repeat 0))
+                      final-polymer)
+      unique-counts (filter pos? (map #(Math/ceil (/ (val %) 2)) letter-counts))]
+  (println (- (apply max unique-counts) (apply min unique-counts))))
+
diff --git a/year2021/day15/part1.clj b/year2021/day15/part1.clj
new file mode 100644 (file)
index 0000000..7838e34
--- /dev/null
@@ -0,0 +1,30 @@
+(def input (->> (slurp "./in")
+                (clojure.string/split-lines)
+                (mapv (partial mapv (comp read-string str)))
+                (#(for [y (range 0 (count %)) x (range 0 (count (first %)))]
+                    {[y x] (get-in % [y x])}))
+                (into {})))
+
+(def dim (apply max (map first (keys input))))
+
+(defn find-neighbors [u]
+  (filter #(contains? input %) [(update u 0 inc)
+                                (update u 0 dec)
+                                (update u 1 inc)
+                                (update u 1 dec)]))
+
+(loop [dist (zipmap (keys input) (repeat ##Inf))
+       Q    {[0 0] 0}]
+  (if (empty? Q)
+    (println (dist [dim dim]))
+    (let [[u distu] (first Q)
+          NN (reduce
+               #(let [dv (+ distu (input %2))]
+                  (cond-> %1
+                    (> ((first %1) %2) dv)
+                    (-> (update 0 assoc %2 dv)
+                        (update 1 assoc %2 dv))))
+               [dist {}]
+               (find-neighbors u))]
+      (recur (first NN) (sort-by val < (into (rest Q) (second NN)))))))
+
diff --git a/year2021/day15/part2.clj b/year2021/day15/part2.clj
new file mode 100644 (file)
index 0000000..a422ed0
--- /dev/null
@@ -0,0 +1,41 @@
+(def input (->> (slurp "./in")
+                (clojure.string/split-lines)
+                (mapv (partial mapv (comp read-string str)))
+                (#(for [y (range 0 (count %)) x (range 0 (count (first %)))]
+                    {[y x] (get-in % [y x])}))
+                (into {})
+                ((fn [lst]
+                (reduce
+                  #(into %1
+                     (for [j (range 0 5) i (range 0 5)]
+                       {[(+ (first (key %2)) (* 100 j)) (+ (second (key %2)) (* 100 i))]
+                        (let [s (+ i j (val %2))] (if (> s 9) (- s 9) s))}))
+                  {}
+                  lst
+                  )))
+                (into {})
+                ))
+
+(def dim (apply max (map first (keys input))))
+
+(defn find-neighbors [u]
+  (filter #(contains? input %) [(update u 0 inc)
+                                (update u 0 dec)
+                                (update u 1 inc)
+                                (update u 1 dec)]))
+
+(loop [dist (zipmap (keys input) (repeat ##Inf))
+       Q    {[0 0] 0}]
+  (if (empty? Q)
+    (println (dist [dim dim]))
+    (let [[u distu] (first Q)
+          NN (reduce
+               #(let [dv (+ distu (input %2))]
+                  (cond-> %1
+                    (> ((first %1) %2) dv)
+                    (-> (update 0 assoc %2 dv)
+                        (update 1 assoc %2 dv))))
+               [dist {}]
+               (find-neighbors u))]
+      (recur (first NN) (sort-by val < (into (rest Q) (second NN)))))))
+
diff --git a/year2021/day16/part1.clj b/year2021/day16/part1.clj
new file mode 100644 (file)
index 0000000..2358e59
--- /dev/null
@@ -0,0 +1,67 @@
+(require '[clojure.string :as str])
+(require '[clojure.set :as set])
+
+(def hex-lookup
+  {\0 "0000" \1 "0001" \2 "0010" \3 "0011"
+   \4 "0100" \5 "0101" \6 "0110" \7 "0111"
+   \8 "1000" \9 "1001" \A "1010" \B "1011"
+   \C "1100" \D "1101" \E "1110" \F "1111"})
+
+(defn binary-to-num [binstr]
+  (reduce
+    #(cond-> %1 true (* 2) (= \1 %2) inc)
+    0
+    binstr))
+
+(defn take-packet-version [packet]
+  (-> (split-at 3 packet)
+      (update 0 binary-to-num)))
+
+(defn take-literal-value [packet]
+  (let [[tid data] (split-at 3 packet)]
+    (when (= '(\1 \0 \0) tid)
+      (let [sd   (into [] data)
+            spl  (split-with #(= \1 (first %)) (partition 5 sd))
+            nums (map rest (concat (first spl) (take 1 (second spl))))]
+        [(binary-to-num (reduce concat nums))
+         (drop (* 5 (inc (count (first spl)))) sd)]
+        ))))
+
+(defn take-operator [packet]
+  (let [id (first packet) ps (str/join (rest packet))]
+    (if (= \0 id)
+      (let [bits (binary-to-num (subs ps 0 15))]
+        [(subs ps 15) bits :bits])
+      (let [pkts (binary-to-num (subs ps 0 11))]
+        [(subs ps 11) pkts :pkts]))))
+
+(defn process-packet [[input vcnt]]
+  (let [[version data] (take-packet-version input)]
+    (if (every? #(= \0 %) data)
+      ['() vcnt]
+      (do
+        (if-let [value (take-literal-value data)]
+          [(second value) (+ vcnt version)]
+          (do
+            (let [info (take-operator (drop 3 data))]
+              (if (= :bits (get info 2))
+                (loop [inpt [(subs (first info) 0 (get info 1)) (+ vcnt version)]]
+                  (if (empty? (first inpt))
+                    [(subs (first info) (get info 1)) (second inpt)]
+                    (recur (process-packet inpt))))
+                (loop [n (get info 1) inpt [(get info 0) (+ vcnt version)]]
+                  (if (pos? n)
+                    (recur (dec n) (process-packet inpt))
+                    inpt))))))))))
+
+(loop [packet (->> (slurp "./in")
+                   (map hex-lookup)
+                   (take-while some?)
+                   (reduce concat)
+                   (str/join)
+                   (#(vector % 0))
+                   (process-packet))]
+  (if (not (empty? (first packet)))
+    (recur (process-packet packet))
+    (println (second packet))))
+
diff --git a/year2021/day16/part2.cpp b/year2021/day16/part2.cpp
new file mode 100644 (file)
index 0000000..5a02df9
--- /dev/null
@@ -0,0 +1,131 @@
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <list>
+#include <map>
+#include <string>
+#include <string_view>
+#include <tuple>
+
+static const std::map<char, const char *> hexToBin = {
+    {'0', "0000"}, {'1', "0001"}, {'2', "0010"}, {'3', "0011"},
+    {'4', "0100"}, {'5', "0101"}, {'6', "0110"}, {'7', "0111"},
+    {'8', "1000"}, {'9', "1001"}, {'A', "1010"}, {'B', "1011"},
+    {'C', "1100"}, {'D', "1101"}, {'E', "1110"}, {'F', "1111"}
+};
+
+static std::pair<uint64_t, std::string_view> solve(std::string_view packet);
+
+int main(int argc, const char *argv[])
+{
+    if (argc != 2)
+        return -1;
+
+    std::string packetBin;
+    std::string packetHex (argv[1]);
+    for (char c : packetHex)
+        packetBin += hexToBin.at(c);
+
+    std::cout << solve(packetBin).first << std::endl;
+
+    return 0;
+}
+
+uint64_t binStrToInt(std::string_view bin)
+{
+    uint64_t n = 0;
+
+    for (char c : bin) {
+        n = n * 2ull;
+        if (c == '1')
+            ++n;
+    }
+
+    return n;
+}
+
+bool isEmptyPacket(std::string_view packet)
+{
+    return packet.empty() ||
+           std::all_of(packet.cbegin(), packet.cend(),
+                       [](char c) { return c == '0'; });
+}
+
+std::pair<uint64_t, std::string_view> solve(std::string_view packet)
+{
+    // Remove version
+    packet = packet.substr(3);
+    // Pull type ID
+    const auto typeId = packet.substr(0, 3);
+    packet = packet.substr(3);
+    
+    if (typeId == "100") {
+        std::string numberStr;
+        while (1) {
+            const auto chunk = packet.substr(0, 5);
+            packet = packet.substr(5);
+            numberStr += chunk.substr(1);
+            if (chunk.front() == '0')
+                break;
+        }
+
+        return {binStrToInt(numberStr), isEmptyPacket(packet) ? "" : packet};
+    } else {
+        const bool isLengthBits = packet.front() == '0';
+        packet = packet.substr(1);
+        const auto lengthStr = packet.substr(0, isLengthBits ? 15 : 11);
+        const auto length = binStrToInt(lengthStr);
+        packet = packet.substr(isLengthBits ? 15 : 11);
+
+        std::list<uint64_t> args;
+        if (isLengthBits) {
+            auto rem = packet.substr(0, length);
+            while (1) {
+                const auto ret = solve(rem);
+                args.emplace_front(ret.first);
+                if (ret.second.empty() || isEmptyPacket(ret.second))
+                    break;
+                rem = ret.second;
+            }
+            packet = packet.substr(length);
+        } else {
+            for (uint64_t i = 0; i < length; ++i) {
+                const auto ret = solve(packet);
+                args.emplace_front(ret.first);
+                packet = ret.second;
+                if (isEmptyPacket(packet))
+                    break;
+            }
+        }
+
+        uint64_t result;
+        if (typeId == "000") {
+            result = 0;
+            for (auto a : args)
+                result += a;
+        } else if (typeId == "001") {
+            result = 1;
+            for (auto a : args)
+                result *= a;
+        } else if (typeId == "010") {
+            result = *std::min_element(args.cbegin(), args.cend());
+        } else if (typeId == "011") {
+            result = *std::max_element(args.cbegin(), args.cend());
+        } else if (typeId == "101") {
+            const auto a1 = args.back();
+            args.pop_back();
+            result = args.back() < a1;
+        } else if (typeId == "110") {
+            const auto a1 = args.back();
+            args.pop_back();
+            result = args.back() > a1;
+        } else if (typeId == "111") {
+            const auto a1 = args.back();
+            args.pop_back();
+            result = args.back() == a1;
+        }
+
+        return {result, isEmptyPacket(packet) ? "" : packet};
+    }
+}
+
diff --git a/year2021/day17/part3.clj b/year2021/day17/part3.clj
new file mode 100644 (file)
index 0000000..ae51260
--- /dev/null
@@ -0,0 +1,59 @@
+;
+;
+; Put into a lein project so that you can pass Java more RAM (e.g. -Xmx15G)
+; https://www.reddit.com/r/adventofcode/comments/riqtwx/2021_day_17_day_17_part_3/
+;
+;
+
+(require '[clojure.core.reducers :as r])
+
+(def target-area [[20000 -5000] [30000 -10000]])
+(def initial-pos [0 0])
+
+(defn beyond-target? [[[tbx tby] [tex tey]] [x y]]
+  (or (> x tex) (< y tey)))
+
+(defn within-target? [[[tbx tby] [tex tey]] [x y]]
+  (and (>= x tbx) (<= x tex) (<= y tby) (>= y tey)))
+
+(defn apply-velocity [[[px py] [vx vy]]]
+  [[(+ px vx) (+ py vy)] [(cond-> vx (pos? vx) dec) (dec vy)]])
+
+(defn take-last-while [pred coll]
+  (loop [v (first coll) r (rest coll)]
+    (if (not (pred (first r)))
+      v
+      (recur (first r) (rest r)))))
+
+(defn build-path [target vel]
+  (->> (iterate apply-velocity [initial-pos vel])
+       (take-last-while (comp not (partial beyond-target? target) first))
+       (first)))
+
+; Used to determine best x velocity for highest path
+(def tnum-seq (iterate #(do [(apply + %) (inc (second %))]) [0 1]))
+
+(let [[tb te]      target-area
+      lowest-x     (second (last (take-while #(< (first %) (first tb)) tnum-seq)))
+      highest-y    (dec (Math/abs (second te)))]
+  (->> (for [y (range (second te) (inc highest-y))
+             x (range lowest-x (inc (first te)))] [x y])
+       (#(do (println "Generated xy pairs...") %))
+       (#(do (println "Total: " (* (- highest-y (second te)) (- (inc highest-y) lowest-x))) %))
+       (partition 1000000)
+       (#(do (println "Prepared partitions...") %))
+       (reduce
+          (fn [sum nlst]
+            (println sum)
+            (+ sum
+              (r/fold +
+                (r/monoid
+                  (fn [tot xy]
+                    (cond-> tot
+                      (within-target? target-area (build-path target-area xy))
+                      inc))
+                  (constantly 0))
+                (into [] nlst))))
+           0)
+       (println)))
+
diff --git a/year2021/day17/partboth.clj b/year2021/day17/partboth.clj
new file mode 100644 (file)
index 0000000..c585bf9
--- /dev/null
@@ -0,0 +1,54 @@
+(require '[clojure.core.reducers :as r])
+
+;(def target-area [[169 -68] [206 -108]])
+(def target-area [[20000 -5000] [30000 -10000]])
+;(def target-area [[2000 -500] [3000 -1000]])
+(def initial-pos [0 0])
+
+(defn beyond-target? [[[tbx tby] [tex tey]] [x y]]
+  (or (> x tex) (< y tey)))
+
+(defn within-target? [[[tbx tby] [tex tey]] [x y]]
+  (and (>= x tbx) (<= x tex) (<= y tby) (>= y tey)))
+
+(defn apply-velocity [[[px py] [vx vy]]]
+  [[(+ px vx) (+ py vy)] [(cond-> vx (pos? vx) dec) (dec vy)]])
+
+(defn take-last-while [pred coll]
+  (loop [v (first coll) r (rest coll)]
+    (if (not (pred (first r)))
+      v
+      (recur (first r) (rest r)))))
+
+(defn build-path [target vel]
+  (->> (iterate apply-velocity [initial-pos vel])
+       (take-last-while (comp not (partial beyond-target? target) first))
+       (first)))
+
+; Used to determine best x velocity for highest path
+(def tnum-seq (iterate #(do [(apply + %) (inc (second %))]) [0 1]))
+
+(let [[tb te]      target-area
+      lowest-x     (second (last (take-while #(< (first %) (first tb)) tnum-seq)))
+      highest-y    (dec (Math/abs (second te)))]
+  (->> (for [y (range (second te) (inc highest-y))
+             x (range lowest-x (inc (first te)))] [x y])
+       (#(do (println "Generated xy pairs...") %))
+       (#(do (println "Total: " (* (- highest-y (second te)) (- (inc highest-y) lowest-x))) %))
+       (partition 50000)
+       (#(do (println "Prepared partitions...") %))
+       (reduce
+          (fn [sum nlst]
+            (println sum)
+            (+ sum
+              (r/fold +
+                (r/monoid
+                  (fn [tot xy]
+                    (cond-> tot
+                      (within-target? target-area (build-path target-area xy))
+                      inc))
+                  (constantly 0))
+                (into [] nlst))))
+           0)
+       (println)))
+
diff --git a/year2021/day18/partboth.clj b/year2021/day18/partboth.clj
new file mode 100644 (file)
index 0000000..83fc42c
--- /dev/null
@@ -0,0 +1,95 @@
+(require '[clojure.core.reducers :as r])
+(require '[clojure.set :as set])
+(require '[clojure.zip :as z])
+
+(defn zip-depth [loc]
+  (loop [l loc d 0] (if (nil? l) d (recur (z/up l) (inc d)))))
+
+(defn zip-prev-num [loc]
+  (loop [l loc]
+    (if-let [prev (z/prev l)]
+      (if (not (z/branch? prev))
+        prev
+        (recur prev)))))
+
+(defn zip-next-num [loc]
+  (loop [l loc]
+    (if-let [nxt (z/next l)]
+      (if (not (z/branch? nxt))
+        (when (some? (z/node nxt)) nxt)
+        (recur nxt)))))
+
+(defn snailfish-explode [tree]
+  (loop [node (z/vector-zip tree)]
+    (if (z/end? node)
+      node
+      (if (and (z/branch? node)
+               (= 2 (count (z/children node)))
+               (and (not (z/branch? (z/down node))) (not (z/branch? (z/next (z/down node)))))
+               (> (zip-depth node) 5))
+        (let [children (z/children node)
+              nnode    (z/replace node 0)]
+          (if-let [prev (zip-prev-num nnode)]
+            (z/root
+              (let [new-prev (z/edit prev + (first children))]
+                (if-let [nxt (nth (iterate zip-next-num new-prev) 2)]
+                  (z/edit nxt + (second children))
+                  new-prev)))
+            (when-let [nxt (zip-next-num nnode)]
+              (z/root (z/edit nxt + (second children))))))
+        (recur (z/next node))))))
+
+(defn snailfish-split [tree]
+  (loop [node (z/vector-zip tree)]
+    (if (or (z/end? node) (nil? (z/node node)))
+      node
+      (if (and (not (z/branch? node)) (> (z/node node) 9))
+        (z/root
+          (z/replace node
+            (z/make-node node (z/node node)
+              (map long [(Math/floor (/ (z/node node) 2))
+                         (Math/ceil (/ (z/node node) 2))]))))
+        (recur (z/next node))))))
+
+(defn snailfish-magnitude [ntree]
+    (if (= 2 (count (z/children ntree)))
+      (let [cl (z/down ntree) cr (z/right cl)]
+        (+ (* 3 (if (z/branch? cl) (snailfish-magnitude cl) (z/node cl)))
+           (* 2 (if (z/branch? cr) (snailfish-magnitude cr) (z/node cr)))))
+      (loop [node (z/down ntree) sum 0]
+        (if (nil? node)
+          sum
+          (recur (z/right node)
+                 (+ sum (if (z/branch? node) (snailfish-magnitude node) (z/node node))))))))
+
+(defn snailfish-solve [add-list]
+  (snailfish-magnitude
+    (loop [result     (z/vector-zip (vec (take 2 add-list)))
+           next-input (drop 2 add-list)]
+      (let [explode (snailfish-explode result)]
+        (if (nil? (second explode))
+          (recur explode next-input)
+          (let [splt (snailfish-split result)]
+            (if (nil? (second splt))
+              (recur splt next-input)
+              (if (empty? next-input)
+                result
+                (recur (z/vector-zip
+                         [(vec (z/children result)) (first next-input)])
+                       (rest next-input))))))))))
+
+; Build input list
+(def input (->> (slurp "./in")
+                clojure.string/split-lines
+                (map read-string)))
+
+; Part 1
+(println (snailfish-solve input))
+
+; Part 2
+(->> (for [in input in2 input :when (not= in in2)] [in in2])
+     (vec)
+     (r/map snailfish-solve)
+     (r/fold (r/monoid max (constantly 0)))
+     (println))
+
diff --git a/year2021/day19/partboth.clj b/year2021/day19/partboth.clj
new file mode 100644 (file)
index 0000000..48f1a9c
--- /dev/null
@@ -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)))))))
+
diff --git a/year2021/day2/part1.clj b/year2021/day2/part1.clj
new file mode 100644 (file)
index 0000000..e4e9d49
--- /dev/null
@@ -0,0 +1,26 @@
+; Day 2, part 1
+; Read a list of instructions from stdin:
+;   "down X" increases depth number by X,
+;   "up X" decreases depth by X,
+;   "forward X" increases xpos by X.
+; Print (xpos * depth) after end of data.
+;
+
+(require '[clojure.string :as str])
+
+(println
+  (reduce *
+    (vals
+      (reduce
+        #(case (first %2)
+           "forward" (update %1 :xpos  + (second %2))
+           "up"      (update %1 :depth - (second %2))
+           "down"    (update %1 :depth + (second %2))
+           )
+        {:xpos 0 :depth 0}
+        (->> (slurp "./in")
+             str/split-lines
+             (map #(str/split % #" "))
+             (map #(update % 1 read-string))
+             )))))
+
diff --git a/year2021/day2/part2.clj b/year2021/day2/part2.clj
new file mode 100644 (file)
index 0000000..9487a49
--- /dev/null
@@ -0,0 +1,27 @@
+; Day 2, part 2
+; Read a list of instructions from stdin:
+;   "down X" increases aim number by X,
+;   "up X" decreases aim by X,
+;   "forward X" increases xpos by X and depth by (aim * X).
+; Print (xpos * depth) after end of data.
+;
+
+(require '[clojure.string :as str])
+
+(println
+  (apply *
+    (map
+      (reduce
+        #(case (first %2)
+           "forward" (-> %1 (update :xpos + (second %2))
+                            (update :depth + (* (%1 :aim) (second %2))))
+           "up"      (update %1 :aim - (second %2))
+           "down"    (update %1 :aim + (second %2)))
+        {:xpos 0 :depth 0 :aim 0}
+        (->> (slurp "./in")
+             str/split-lines
+             (map #(str/split % #" "))
+             (map #(update % 1 read-string))))
+      [:xpos :depth]
+      )))
+
diff --git a/year2021/day20/partboth.clj b/year2021/day20/partboth.clj
new file mode 100644 (file)
index 0000000..33a4d4f
--- /dev/null
@@ -0,0 +1,43 @@
+(require '[clojure.string :as str])
+
+(defn pad-input-map [in-map pad-val]
+  (let [ly (count in-map) lx (count (first in-map))
+        sy (+ 4 ly) sx (+ 4 lx)
+        buffer (byte-array (repeat (* sy sx) pad-val))]
+    (doseq [y (range 0 ly) x (range 0 lx)]
+      (aset-byte buffer (+ (* sx (+ 2 y)) 2 x) (get-in in-map [y x])))
+    (mapv vec (partition sx buffer))))
+
+(defn get-number [in-map y x]
+  (map (partial get-in in-map)
+       [[(dec y) (dec x)] [(dec y) x] [(dec y) (inc x)]
+        [y (dec x)]       [y x]       [y (inc x)]
+        [(inc y) (dec x)] [(inc y) x] [(inc y) (inc x)]]))
+
+(defn get-new-pixel [enhance-algo in-map y x]
+  (->> (get-number in-map y x)
+       (reduce #(cond-> (* 2 %1) (= 1 %2) inc) 0)
+       (get enhance-algo)))
+
+(defn build-output-number-map [enhance-algo in-map]
+  (let [pad-val (if (pos? (first enhance-algo)) (first (first in-map)) 0)
+        padded-in-map (pad-input-map in-map pad-val)]
+    (->> (for [y (range 1 (dec (count padded-in-map)))]
+           (future
+             (mapv (partial get-new-pixel enhance-algo padded-in-map y)
+                   (range 1 (dec (count (first padded-in-map)))))))
+         (mapv deref))))
+
+(defn count-lit-pixels [in-map] ((frequencies (flatten in-map)) 1))
+
+(let [[enhance-algo in-map]
+      (->> (slurp "./in")
+           str/split-lines
+           ((juxt (comp (partial mapv {\. 0 \# 1}) first)
+                  (comp (partial mapv #(mapv {\. 0 \# 1} %)) (partial drop 2)))))
+      image-output (iterate (partial build-output-number-map enhance-algo) in-map)]
+  (println "Part 1:" (count-lit-pixels (nth image-output 2)))
+  (println "Part 2:" (count-lit-pixels (nth image-output 50))))
+
+(shutdown-agents)
+
diff --git a/year2021/day21/part1.clj b/year2021/day21/part1.clj
new file mode 100644 (file)
index 0000000..174f5a1
--- /dev/null
@@ -0,0 +1,22 @@
+(require 'clojure.string)
+
+(loop [player-positions   (->> (slurp "./in")
+                               clojure.string/split-lines
+                               (map (comp read-string second #(clojure.string/split % #": ")))
+                               (mapv #(drop (dec %) (cycle (range 1 11)))))
+       player-scores      (into [] (repeat (count player-positions) 0))
+       player-turn        (cycle (range 0 (count player-scores)))
+       deterministic-dice (cycle (range 1 101))
+       dice-roll-count    0]
+  (if-not (every? #(< % 1000) player-scores)
+    (println (* dice-roll-count (apply min player-scores)))
+    (let [roll         (reduce + (take 3 deterministic-dice))
+          turn         (first player-turn)
+          new-position (drop roll (get player-positions turn))]
+      (recur
+        (assoc player-positions turn new-position)
+        (update player-scores turn + (first new-position))
+        (next player-turn)
+        (drop 3 deterministic-dice)
+        (+ dice-roll-count 3)))))
+
diff --git a/year2021/day21/part2.clj b/year2021/day21/part2.clj
new file mode 100644 (file)
index 0000000..0042aaa
--- /dev/null
@@ -0,0 +1,37 @@
+(defn dice-probability-spread [sides rolls]
+  (let [sr (range 1 (inc sides))]
+    (->> sr
+         (iterate #(flatten (for [i sr] (map (partial + i) %))))
+         (drop (dec rolls))
+         ((comp frequencies first)))))
+
+(def rolls (dice-probability-spread 3 3))
+
+(defn advance-pos [pos roll] (let [n (+ pos roll)] (if (> n 10) (- n 10) n)))
+
+(defn add-roll [state roll p1-turn]
+  (let [pos   (if p1-turn :pos1 :pos2)
+        score (if p1-turn :score1 :score2)
+        new-pos (advance-pos (state pos) roll)]
+    (-> state
+        (assoc pos new-pos)
+        (update score + new-pos))))
+
+(defonce wins (atom [0 0]))
+
+(loop [turn 0 states {{:pos1 4 :score1 0 :pos2 8 :score2 0} 1}]
+  (if (empty? states)
+    (println (apply max @wins))
+    (recur
+      (if (= 0 turn) 1 0)
+      (reduce
+        #(let [kvp (first %2)]
+           (if (< ((key kvp) (if (= 0 turn) :score1 :score2)) 21)
+             (if (contains? %1 (key kvp))
+               (update %1 (key kvp) +' (val kvp))
+               (conj %1 kvp))
+             (do (swap! wins update turn +' (val kvp)) %1)))
+        {}
+        (for [s states r rolls]
+          {(add-roll (first s) (key r) (= 0 turn)) (*' (second s) (val r))})))))
+
diff --git a/year2021/day22/part1.clj b/year2021/day22/part1.clj
new file mode 100644 (file)
index 0000000..bffc1a9
--- /dev/null
@@ -0,0 +1,25 @@
+(require '[clojure.string :as str])
+
+(def input (->> (slurp "./in")
+                (str/split-lines)
+                (map
+                  (fn [line]
+                    [(if (str/starts-with? line "on") true false)
+                     (->> (str/split line #"[^-\d]+")
+                          (rest)
+                          (map #(Integer/parseInt %))
+                          (partition 2))]))))
+
+(println
+  (frequencies
+    (vals
+      (reduce
+        (fn [cmap c]
+          (into cmap
+            (let [[xx yy zz] (second c)]
+              (for [x (range (max -50 (first xx)) (inc (min 50 (second xx))))
+                    y (range (max -50 (first yy)) (inc (min 50 (second yy))))
+                    z (range (max -50 (first zz)) (inc (min 50 (second zz))))]
+                [[x y z] (first c)]))))
+        {} input))))
+
diff --git a/year2021/day22/part2.clj b/year2021/day22/part2.clj
new file mode 100644 (file)
index 0000000..c5d2803
--- /dev/null
@@ -0,0 +1,60 @@
+(require '[clojure.core.reducers :as r])
+(require '[clojure.string :as str])
+
+(def input (->> (slurp "./in")
+                (str/split-lines)
+                (map
+                  (fn [line]
+                    [(if (str/starts-with? line "on") true false)
+                     (->> (str/split line #"[^-\d]+")
+                          (rest)
+                          (map #(Integer/parseInt %))
+                          (partition 2)
+                          (mapv vec))]))
+                (reverse)))
+
+(defn build-coord-list [coords idx]
+  (->> coords
+       (map #(update (get (second %) idx) 1 inc))
+       (flatten)
+       (sort)
+       (vec)))
+
+(defn filter-coord-list [coords idx v]
+  (filter
+    #(let [[p0 p1] (get (second %) idx)]
+       (and (<= p0 v) (<= v p1)))
+    coords))
+
+(def xs (build-coord-list input 0))
+(def ys (build-coord-list input 1))
+(def zs (build-coord-list input 2)) 
+
+(defonce on-count (atom 0))
+
+(loop [x xs]
+  (when-not (empty? (rest x))
+    (println "x=" (first x))
+    (let [inputx (filter-coord-list input 0 (first x))]
+      (swap! on-count +
+        (r/fold
+          32
+          +
+          (fn [onc2 iy]
+            (let [inputy (filter-coord-list inputx 1 (get ys iy))]
+              (+ onc2
+                (reduce
+                  (fn [onc iz]
+                    (let [inputz (first (filter-coord-list inputy 2 (get zs iz)))]
+                      (cond-> onc
+                        (first inputz)
+                        (+ (* (- (second x) (first x))
+                              (- (get ys (inc iy)) (get ys iy))
+                              (- (get zs (inc iz)) (get zs iz)))))))
+                  0
+                  (range 0 (dec (count zs)))))))
+          (into [] (range 0 (dec (count ys))))))
+      (recur (rest x)))))
+
+(println @on-count)
+
diff --git a/year2021/day23/part1-done-by-hand b/year2021/day23/part1-done-by-hand
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/year2021/day23/part2.clj b/year2021/day23/part2.clj
new file mode 100644 (file)
index 0000000..adbefc1
--- /dev/null
@@ -0,0 +1,90 @@
+(require '[clojure.core.reducers :as r])
+
+(def init-field
+  [nil
+   nil
+   (seq [:b :d :d :d])
+   nil
+   (seq [:b :c :b :a])
+   nil
+   (seq [:c :b :a :a])
+   nil
+   (seq [:d :a :c :c])
+   nil
+   nil])
+
+(defn do-slot [[field energy] idx]
+  (let [slot (get field idx)]
+    (cond
+      ; Moving value out of a room
+      (and (seq? slot)
+           (not (empty? slot))
+           (not (every? #(= % ({2 :a 4 :b 6 :c 8 :d} idx)) slot)))
+      (let [open-slots
+            (filterv
+              #(contains? #{0 1 3 5 7 9 10} %)
+              (concat
+                (for [i (reverse (range 0 idx))
+                      :while (or (nil? (get field i)) (seq? (get field i)))] i)
+                (for [i (range idx (count field))
+                      :while (or (nil? (get field i)) (seq? (get field i)))] i)))]
+        (when-not (empty? open-slots)
+          (map
+            (fn [os]
+              [(-> field
+                   (assoc os (first slot))
+                   (update idx rest))
+               (+ energy (* ({:a 1 :b 10 :c 100 :d 1000} (first slot))
+                            (+ (inc (- 4 (count slot))) (Math/abs (- os idx)))))])
+            open-slots)))
+      ; Moving value into a room
+      (and (not (seq? slot)) (some? slot))
+      (let [our-room ({:a 2 :b 4 :c 6 :d 8} slot)]
+        (if (every? #(or (nil? (get field %)) (seq? (get field %)))
+                    (range (inc (min our-room idx)) (max our-room idx)))
+          (let [room (get field our-room)]
+            (when (or (empty? room) (every? #(= slot %) room))
+              [(-> field
+                   (assoc idx nil)
+                   (update our-room conj slot))
+               (+ energy (* ({:a 1 :b 10 :c 100 :d 1000} slot)
+                            (+ (Math/abs (- idx our-room)) (- 4 (count room)))))])))))))
+
+(defn winner? [[field q s]]
+  (= field
+    [nil
+     nil
+     (seq [:a :a :a :a])
+     nil
+     (seq [:b :b :b :b])
+     nil
+     (seq [:c :c :c :c])
+     nil
+     (seq [:d :d :d :d])
+     nil
+     nil]))
+
+(defn do-turns [fields]
+  (into #{}
+    (r/fold
+      r/cat
+      #(if-let [t (apply do-slot %2)]
+         (if (seq? t)
+           (reduce r/append! %1 t)
+           (r/append! %1 t))
+         %1)
+      (into [] (for [f fields i (range 0 11)] [f i])))))
+
+(defn play-games [turns tc]
+  (println "Games:" (count turns) "Turn:" tc)
+  (let [new-turns (do-turns turns)
+        winners (filter winner? new-turns)]
+    (if (seq winners)
+      (map second winners)
+      (recur new-turns (inc tc)))))
+
+(->> (play-games #{[init-field 0]} 0)
+     sort
+     first
+     ((partial println "Lowest energy:")))
+
diff --git a/year2021/day24/checker.clj b/year2021/day24/checker.clj
new file mode 100644 (file)
index 0000000..4874f62
--- /dev/null
@@ -0,0 +1,47 @@
+(require '[clojure.string :as str])
+
+(defn alu-parse-argument [arg]
+  (if (contains? #{\w \x \y \z} (first arg))
+    (str/join ["@" arg])
+    (read-string arg)))
+
+(defn alu-parse-instruction [[ins arg1 arg2]]
+  (let [arg2-parsed (if (some? arg2) (alu-parse-argument arg2) 0)]
+    (case ins
+      "inp"
+      (str/join ["(reset! " arg1 " (- (int (get input (swap! index inc))) 48))\n"])
+      "add"
+      (str/join ["(swap! " arg1 " +' " arg2-parsed ")\n"])
+      "mul"
+      (str/join ["(swap! " arg1 " *' " arg2-parsed ")\n"])
+      "div"
+      (str/join ["(swap! " arg1 " quot " arg2-parsed ")\n"])
+      "mod"
+      (str/join ["(swap! " arg1 " rem " arg2-parsed ")\n"])
+      "eql"
+      (str/join ["(swap! " arg1 " #(if (= % " arg2-parsed ") 1 0))\n"]))))
+
+(def alu-program-header
+    "(defn alu-program [input]
+     (let [index (atom -1) w (atom 0) x (atom 0) y (atom 0) z (atom 0)]\n")
+
+(defn alu-compile-program [instructions]
+  (let [parsed-ins (mapv alu-parse-instruction instructions)]
+    (eval (read-string
+      (str/join [alu-program-header
+                 (str/join parsed-ins)
+                 "@z))"])))))
+
+(def program (->> (slurp "./in")
+                  str/split-lines
+                  (map #(str/split % #"\s+"))
+                  (alu-compile-program)))
+
+; to split by `inp w`s:
+;                  (partition 18)
+;                  (reverse)
+;                  (mapv alu-compile-program)))
+
+(println "Part 1:" (program "16181111641521"))
+(println "Part 2:" (program "59692994994998"))
+
diff --git a/year2021/day24/partboth.clj b/year2021/day24/partboth.clj
new file mode 100644 (file)
index 0000000..9548ec3
--- /dev/null
@@ -0,0 +1,41 @@
+(require '[clojure.string :as str])
+
+; The given program operates on a base-26 stack, either pushing or
+; (conditionally) popping values. This code extracts those operations
+; from the input, then works through them to determine the highest
+; and lowest values that produce an output of zero.
+; See the .md file in this directory for more info.
+
+(def program (->> (slurp "./in")
+                  str/split-lines
+                  (map #(str/split % #"\s+"))
+                  (partition 18)
+                  (map (fn [step]
+                    (if (= "1" (last (nth step 4)))
+                      [:push (read-string (last (nth step 15)))]
+                      [:pop (read-string (last (nth step 5)))])
+                    ))))
+
+(defn program-index [prog] (- 14 (count prog)))
+
+(loop [numbers (vec (repeat 2 (vec (repeat 14 0))))
+       stack '()
+       prog program]
+  (if-let [step (first prog)]
+    (if (= :push (first step))
+      (recur numbers
+             (conj stack [(program-index prog) (second step)])
+             (rest prog))
+      (let [i2     (program-index prog)
+            [i1 v] (first stack)
+            diff   (+ v (second step))]
+        (recur
+          [(if (neg? diff)
+             (-> (first numbers) (assoc i1 9) (assoc i2 (+ 9 diff)))
+             (-> (first numbers) (assoc i2 9) (assoc i1 (- 9 diff))))
+           (if (neg? diff)
+             (-> (second numbers) (assoc i2 1) (assoc i1 (- 1 diff)))
+             (-> (second numbers) (assoc i1 1) (assoc i2 (+ 1 diff))))]
+          (rest stack) (rest prog))))
+  (println (map str/join numbers))))
+
diff --git a/year2021/day24/solved-by-hand-with-help.md b/year2021/day24/solved-by-hand-with-help.md
new file mode 100644 (file)
index 0000000..1ddf03e
--- /dev/null
@@ -0,0 +1,4 @@
+Went through this wonderful guide:
+
+[https://github.com/mrphlip/aoc/blob/master/2021/24.md](https://github.com/mrphlip/aoc/blob/master/2021/24.md)
+
diff --git a/year2021/day25/part1.clj b/year2021/day25/part1.clj
new file mode 100644 (file)
index 0000000..df2947c
--- /dev/null
@@ -0,0 +1,40 @@
+(require '[clojure.string :as str])
+
+(defn cucumber-step-east [cuc-map]
+  (for [cuc-row cuc-map]
+    (let [shifted-cuc (str/replace cuc-row #">\." ".>")]
+      (if (and (= \> (last cuc-row)) (= \. (first cuc-row)))
+        (-> shifted-cuc
+            (str/replace #">$" ".")
+            (str/replace #"^\." ">"))
+        shifted-cuc))))
+
+(defn cucumber-step-south [cuc-map]
+  (let [extra-cuc-map
+        (conj (vec (cons (last cuc-map) cuc-map)) (first cuc-map))
+        new-extra-cuc-map
+        (for [y (reverse (range 1 (count extra-cuc-map)))]
+          (str/join
+            (for [x (range 0 (count (first cuc-map)))]
+              (cond
+                (and (= \. (get-in extra-cuc-map [y x])) (= \v (get-in extra-cuc-map [(dec y) x])))
+                \v
+                (and (= \v (get-in extra-cuc-map [y x])) (= \. (get-in extra-cuc-map [(inc y) x])))
+                \.
+                :else
+                (get-in extra-cuc-map [y x])))))]
+    (into [] (reverse (rest new-extra-cuc-map)))))
+
+(defn cucumber-seq [cuc-map-init]
+  (iterate (comp cucumber-step-south cucumber-step-east) cuc-map-init))
+
+(def input (->> (slurp "./in")
+                (str/split-lines)
+                (vec)))
+
+(loop [cuc-hist '() cuc-list (cucumber-seq input)]
+  (let [next-cuc (first cuc-list)]
+    (if (or (nil? next-cuc) (= (first cuc-hist) next-cuc))
+      (println "Cucs are stuck! Steps:" (count cuc-hist))
+      (recur (conj cuc-hist next-cuc) (rest cuc-list)))))
+
diff --git a/year2021/day3/part1.clj b/year2021/day3/part1.clj
new file mode 100644 (file)
index 0000000..3fe888e
--- /dev/null
@@ -0,0 +1,25 @@
+(require '[clojure.string :as str])
+
+(->> "./in"
+     (slurp)
+     (str/split-lines)
+     (map (fn [l] (map #(if (= % \1) 1 0) l)))
+     (apply (partial map +))
+     (map #(if (< % 500) \1 \0))
+     (str/join)
+     (#(Integer/parseInt % 2))
+     (#(* % (bit-xor % (dec (int (Math/pow 2 12))))))
+     (println)
+     )
+
+; (->> input data file name
+;      read in entire contents
+;      split contents into array of lines
+;      for each line, transform characters '1'/'0' to numbers
+;      build sum array using the lines
+;      convert back to array of characters
+;      join characters into single string
+;      convert binary string to a number (gamma)
+;      multiply gamma by its bit-inverse (bit length hard-coded)
+;      print results
+
diff --git a/year2021/day3/part2.clj b/year2021/day3/part2.clj
new file mode 100644 (file)
index 0000000..00e656f
--- /dev/null
@@ -0,0 +1,36 @@
+(require '[clojure.string :as str])
+
+(def bitcount 12)
+(def input
+  (->> "./in"
+      (slurp)
+      (str/split-lines)
+      (map #(Integer/parseInt % 2))
+      )
+  )
+
+(defn countbit [lst bit]
+  (->> lst
+       (map #(if (bit-test % bit) 1 0))
+       (apply +)
+       )
+  )
+
+(defn filterbit [lst bit v]
+  (if (= 1 (count lst))
+    lst
+    (filter #(= (bit-test % bit) v) lst)
+    )
+  )
+
+(loop [bit (dec bitcount) lst0 input lst1 input]
+  (if (and (= 1 (count lst0)) (= 1 (count lst1)))
+    (println (map * lst0 lst1))
+    (recur
+      (dec bit)
+      (filterbit lst0 bit (>= (countbit lst0 bit) (/ (count lst0) 2)))
+      (filterbit lst1 bit (< (countbit lst1 bit) (/ (count lst1) 2)))
+      )
+    )
+  )
+
diff --git a/year2021/day4/part1.clj b/year2021/day4/part1.clj
new file mode 100644 (file)
index 0000000..b9fcceb
--- /dev/null
@@ -0,0 +1,70 @@
+(require '[clojure.string :as str])
+
+(def calls
+  (->> (read-line)
+       (#(str/split % #","))
+       (map #(Integer/parseInt %))
+       )
+  )
+
+(defn read-board []
+  (when (some? (read-line))
+    (mapv
+        (fn [line] (->> line
+            (str/join)
+            (str/trim)
+            (#(str/split % #"\s+"))
+            (map #(Integer/parseInt %))
+            )
+          )
+        (repeatedly 5 read-line)
+        )
+    )
+  )
+
+(defn bingo? [board]
+  (some?
+    (some
+      #(every? nil? %)
+      (concat board (apply mapv vector board))
+      )
+    )
+  )
+
+(defn bingo-mark [board n]
+  (mapv (partial replace {n nil}) board)
+  )
+
+(defn get-bingo [init-board]
+  (loop [board init-board nums calls turns 1]
+    (let [new-board (bingo-mark board (first nums))]
+      (if (bingo? new-board)
+        [new-board (first nums) turns]
+        (recur new-board (rest nums) (inc turns))
+        )
+      )
+    )
+  )
+
+(loop [best [999 0] board (read-board)]
+  (if (nil? board)
+    (println best)
+    (let [bingo (get-bingo board)]
+      (recur
+        (if (< (get bingo 2) (first best))
+          [(get bingo 2)
+           (->> (first bingo)
+                (flatten)
+                (filter some?)
+                (apply +)
+                (* (second bingo))
+                )
+           ]
+          best
+          )
+        (read-board)
+        )
+      )
+    )
+  )
+
diff --git a/year2021/day4/part2.clj b/year2021/day4/part2.clj
new file mode 100644 (file)
index 0000000..516e83c
--- /dev/null
@@ -0,0 +1,70 @@
+(require '[clojure.string :as str])
+
+(def calls
+  (->> (read-line)
+       (#(str/split % #","))
+       (map #(Integer/parseInt %))
+       )
+  )
+
+(defn read-board []
+  (when (some? (read-line))
+    (mapv
+        (fn [line] (->> line
+            (str/join)
+            (str/trim)
+            (#(str/split % #"\s+"))
+            (map #(Integer/parseInt %))
+            )
+          )
+        (repeatedly 5 read-line)
+        )
+    )
+  )
+
+(defn bingo? [board]
+  (some?
+    (some
+      #(every? nil? %)
+      (concat board (apply mapv vector board))
+      )
+    )
+  )
+
+(defn bingo-mark [board n]
+  (mapv (partial replace {n nil}) board)
+  )
+
+(defn get-bingo [init-board]
+  (loop [board init-board nums calls turns 1]
+    (let [new-board (bingo-mark board (first nums))]
+      (if (bingo? new-board)
+        [new-board (first nums) turns]
+        (recur new-board (rest nums) (inc turns))
+        )
+      )
+    )
+  )
+
+(loop [best [0 0] board (read-board)]
+  (if (nil? board)
+    (println best)
+    (let [bingo (get-bingo board)]
+      (recur
+        (if (> (get bingo 2) (first best))
+          [(get bingo 2)
+           (->> (first bingo)
+                (flatten)
+                (filter some?)
+                (apply +)
+                (* (second bingo))
+                )
+           ]
+          best
+          )
+        (read-board)
+        )
+      )
+    )
+  )
+
diff --git a/year2021/day5/part1.clj b/year2021/day5/part1.clj
new file mode 100644 (file)
index 0000000..95d04ba
--- /dev/null
@@ -0,0 +1,75 @@
+(require '[clojure.string :as str])
+
+(defn read-coords []
+  (let [line (read-line)]
+    (when (not (empty? line))
+      (mapv
+        #(Integer/parseInt %)
+        (str/split
+          line
+          #"[^\d]+"
+          )
+        )
+      )
+    )
+  )
+
+(defn read-all-coords []
+  (loop [cds [] c (read-coords)]
+    (if (empty? c)
+      cds
+      (recur
+        (conj cds c)
+        (read-coords)
+        )
+      )
+    )
+  )
+
+(defn mark-coord [cmap x y]
+  (update cmap y #(update % x inc))
+  )
+
+(defn mark-coords [cmap x1 y1 x2 y2]
+  (cond
+    (= y1 y2)
+    (reduce
+      #(mark-coord %1 %2 y1)
+      cmap
+      (range (min x1 x2) (inc (max x1 x2)))
+      )
+    (= x1 x2)
+    (reduce
+      #(mark-coord %1 x1 %2)
+      cmap
+      (range (min y1 y2) (inc (max y1 y2)))
+      )
+    :else
+    cmap
+    )
+  )
+
+(defn empty-map []
+  (vec
+    (repeat 1000
+      (vec (repeat 1000 0))
+      )
+    )
+  )
+
+(def finished-map
+  (reduce
+    #(apply (partial mark-coords %1) %2)
+    (empty-map)
+    (read-all-coords)
+    )
+  )
+
+(->> finished-map
+    (flatten)
+    (map dec)
+    (filter pos?)
+    (count)
+    (println)
+    )
+
diff --git a/year2021/day5/part2.clj b/year2021/day5/part2.clj
new file mode 100644 (file)
index 0000000..d324618
--- /dev/null
@@ -0,0 +1,83 @@
+(require '[clojure.string :as str])
+
+(defn read-coords []
+  (let [line (read-line)]
+    (when (not (empty? line))
+      (mapv
+        #(Integer/parseInt %)
+        (str/split
+          line
+          #"[^\d]+"
+          )
+        )
+      )
+    )
+  )
+
+(defn read-all-coords []
+  (loop [cds [] c (read-coords)]
+    (if (empty? c)
+      cds
+      (recur
+        (conj cds c)
+        (read-coords)
+        )
+      )
+    )
+  )
+
+(defn mark-coord [cmap x y]
+  (update
+    cmap
+    [x y]
+    #(if (nil? %) 0 (inc %))
+    )
+  )
+
+(defn mark-coords [cmap x1 y1 x2 y2]
+  (cond
+    (= y1 y2)
+    (reduce
+      #(mark-coord %1 %2 y1)
+      cmap
+      (range (min x1 x2) (inc (max x1 x2)))
+      )
+    (= x1 x2)
+    (reduce
+      #(mark-coord %1 x1 %2)
+      cmap
+      (range (min y1 y2) (inc (max y1 y2)))
+      )
+    :else
+    (let [ic (if (< x1 x2) [x1 y1] [x2 y2])
+          ec (if (> x1 x2) [x1 y1] [x2 y2])
+          dy (if (> (second ec) (second ic)) 1 -1)
+          ]
+      (loop [cm cmap c ic]
+        (if (> (first c) (first ec))
+          cm
+          (recur
+            (apply (partial mark-coord cm) c)
+            [(inc (first c)) (+ dy (second c))]
+            )
+          )
+        )
+      )
+    )
+  )
+
+(def finished-map
+  (reduce
+    #(apply (partial mark-coords %1) %2)
+    {}
+    (read-all-coords)
+    )
+  )
+
+(->> finished-map
+     (vals)
+     (filter pos?)
+     (count)
+     (println)
+     )
+
diff --git a/year2021/day6/consteval.cpp b/year2021/day6/consteval.cpp
new file mode 100644 (file)
index 0000000..f46da89
--- /dev/null
@@ -0,0 +1,32 @@
+#include <algorithm>
+#include <cstdint>
+#include <numeric>
+#include <iostream>
+
+consteval auto countFish(unsigned int day)
+{
+    unsigned char input[] = {
+        //3,4,3,1,2
+#include "in"
+    };
+
+    uint64_t counts[9];
+    std::fill(counts, counts + 9, 0);
+    for (int i = 0; i < sizeof(input); ++i)
+        ++counts[input[i]];
+
+    for (int i = 0; i < day; ++i) {
+        std::rotate(counts, counts + 1, counts + 9);
+        counts[6] += counts[8];
+    }
+
+    return std::accumulate(counts, counts + 9, 0ull);
+}
+
+int main()
+{
+    std::cout << "80: " << countFish(80) << std::endl;
+    std::cout << "256: " << countFish(256) << std::endl;
+    return 0;
+}
+
diff --git a/year2021/day6/part1.clj b/year2021/day6/part1.clj
new file mode 100644 (file)
index 0000000..70293f7
--- /dev/null
@@ -0,0 +1,20 @@
+(require '[clojure.string :as str])
+
+(def fish-init
+  (->> (read-line)
+       (#(str/split % #","))
+       (map #(Integer/parseInt %))
+       (vec)
+       )
+  )
+
+(defn cycle-day [fish]
+  (flatten
+    (for [f (map dec fish)]
+      (if (neg? f) [6 8] f)
+      )
+    )
+  )
+
+(println (count (nth (iterate cycle-day fish-init) 80)))
+
diff --git a/year2021/day6/part2.clj b/year2021/day6/part2.clj
new file mode 100644 (file)
index 0000000..ad6fe91
--- /dev/null
@@ -0,0 +1,25 @@
+(require '[clojure.string :as str])
+
+(->> (read-line)
+     (#(str/split % #","))
+     (map read-string)
+     (reduce #(update %1 %2 inc) (vec (repeat 9 0)))
+     (iterate
+       #(let [nf (conj (vec (rest %)) (first %))]
+          (update nf 6 (partial + (get nf 8)))
+          )
+       )
+     (#(nth % 256))
+     (apply +)
+     (println)
+     )
+
+; ->> read input from stdin
+;     split input string by commas
+;     convert string array into number array
+;     reduce to frequency counts
+;     create iterator that returns next day's counts
+;     get 256th iteration
+;     sum all frequency counts
+;     print results
+
diff --git a/year2021/day7/maxima.mac b/year2021/day7/maxima.mac
new file mode 100644 (file)
index 0000000..a1c2d18
--- /dev/null
@@ -0,0 +1,10 @@
+load("descriptive")$
+load("in.mac")$ /* Should define `input` list of numbers. */
+
+calcfuel(pos, distmod) :=
+    lreduce("+", map(lambda([n], distmod(abs(pos - n))), input))$
+
+calcfuel(median(input), lambda([x],x));
+calcfuel(floor(mean(input)), lambda([x], (x*(x+1)/2)));
+calcfuel(floor(mean(input)) + 1, lambda([x], (x*(x+1)/2)));
+
diff --git a/year2021/day7/part1.clj b/year2021/day7/part1.clj
new file mode 100644 (file)
index 0000000..f08e5b4
--- /dev/null
@@ -0,0 +1,18 @@
+(defn median [lst]
+  (as-> (count lst) $
+    (quot $ 2)
+    (subvec (vec (sort lst)) (dec $) (inc $))
+    (if (even? (count lst)) (apply + $) (second $))
+    (quot $ 2)
+    )
+  )
+
+(as-> (slurp "./in") $ ; "16,1,2,0,4,2,7,1,2,14"
+      (clojure.string/split $ #",")
+      (mapv read-string $)
+      (map (partial - (median $)) $)
+      (map #(Math/abs %) $)
+      (apply + $)
+      (println $)
+      )
+
diff --git a/year2021/day7/part2.clj b/year2021/day7/part2.clj
new file mode 100644 (file)
index 0000000..b96b55d
--- /dev/null
@@ -0,0 +1,20 @@
+(defn calc-fuel [lst pos]
+  (reduce #(as-> %2 $
+             (- pos $)
+             (Math/abs $)
+             (/ (* $ (inc $)) 2)
+             (+ %1 $)
+             )
+          0 lst
+          )
+  )
+
+(let [input (as-> (slurp "./in") $ ;"16,1,2,0,4,2,7,1,2,14"
+                  (clojure.string/split $ #",")
+                  (map read-string $)
+                  )
+      mean (quot (apply + input) (count input))]
+  (println (min (calc-fuel input mean)
+                (calc-fuel input (inc mean))))
+  )
+
diff --git a/year2021/day8/part1.clj b/year2021/day8/part1.clj
new file mode 100644 (file)
index 0000000..fe06fdf
--- /dev/null
@@ -0,0 +1,15 @@
+(require '[clojure.string :as str])
+
+(->> (str/split-lines (slurp "./in"))
+     (map
+       (fn [line]
+         (as-> line $
+           (str/split $ #" ")
+           (subvec $ 11 15)
+           (filter #(.contains [2 3 4 7] (count %)) $)
+           (count $)
+           )))
+     (apply +)
+     (println)
+     )
+
diff --git a/year2021/day8/part2.clj b/year2021/day8/part2.clj
new file mode 100644 (file)
index 0000000..1ee3c08
--- /dev/null
@@ -0,0 +1,66 @@
+(require '[clojure.string :as str])
+(require '[clojure.set :as set])
+
+(defn find-match
+  "
+  Searches for digit that `has segs-left` segments remaining
+  after the segments of `dig-to-cmp` are removed from the
+  digits in `cnts` with `grp-to-cmp` segments.
+  "
+  [segs-left dig-to-cmp cnts grp-to-cmp]
+  (as-> cnts $
+    (filterv #(= (first %) grp-to-cmp) $)
+    (filterv
+      #(-> (second %)
+           (str/replace (re-pattern (str/join ["[" dig-to-cmp "]"])) "")
+           (count)
+           (= segs-left)
+           )
+      $
+      )
+    (get-in $ [0 1])
+    )
+  )
+
+(defn determine-digits [line]
+  (let [counts (mapv #(do [(count %) %]) (take 10 line))
+        mcounts (into {} counts)]
+    (as-> {} $
+        (assoc $ 1 (mcounts 2)
+                 4 (mcounts 4)
+                 7 (mcounts 3)
+                 8 (mcounts 7)
+                 )
+        (assoc $ 3 (find-match 2 ($ 7) counts 5)
+                 6 (find-match 4 ($ 7) counts 6)
+                 2 (find-match 3 ($ 4) counts 5)
+                 9 (find-match 2 ($ 4) counts 6)
+                 )
+        (assoc $ 5 (find-match 2 ($ 2) counts 5))
+        (assoc $ 0 (find-match 2 ($ 5) counts 6))
+        )
+    )
+  )
+
+(println
+  (reduce
+    (fn [sum input]
+      (let [line (as-> input $
+                   (str/split $ #" ")
+                   (mapv (comp str/join sort) $)
+                   )
+            number (subvec line 11 15)
+            decoder (set/map-invert (determine-digits line))]
+        (->> number
+             (map (comp str decoder))
+             (str/join)
+             (#(Integer/parseInt %))
+             (+ sum)
+             )
+        )
+      )
+    0
+    (str/split-lines (slurp "./in"))
+    )
+  )
+
diff --git a/year2021/day9/part1.clj b/year2021/day9/part1.clj
new file mode 100644 (file)
index 0000000..7bd8e23
--- /dev/null
@@ -0,0 +1,21 @@
+(def input-map
+  (->> (slurp "./in")
+       (clojure.string/split-lines)
+       (mapv vec)
+       (mapv (partial mapv #(- (int %) 48)))
+       ))
+
+(defn get-adj [y x]
+  (map (partial get-in input-map)
+       [[(dec y) x] [(inc y) x] [y (dec x)] [y (inc x)]]))
+
+(->> (for [y (range 0 (count input-map))
+           x (range 0 (count (first input-map)))
+           :let [height (get-in input-map [y x])]
+           :when (every? #(or (nil? %) (< height %))
+                         (get-adj y x))]
+           (inc height))
+     (apply +)
+     (println)
+     )
+
diff --git a/year2021/day9/part2.clj b/year2021/day9/part2.clj
new file mode 100644 (file)
index 0000000..3030c4e
--- /dev/null
@@ -0,0 +1,45 @@
+(require '[clojure.set])
+
+(defn get-adj 
+  "Gets vector of coords surrounding (x, y)."
+  [y x] [[(dec y) x] [(inc y) x] [y (dec x)] [y (inc x)]])
+
+(defn basin-continues? 
+  "Determines if `b` is a continuation of the basin that includes `a`."
+  [a b] (and (some? b) (not= b 9) (> b a)))
+
+(defn basin-bottom?
+  "Determines if point `p` in `hmap` is the bottom of a basin surrounded by
+   points `adj`."
+  [hmap p adj]
+  (every?
+    #(let [q (get-in hmap %)] (or (nil? q) (< (get-in hmap p) q)))
+    adj
+    ))
+
+(defn find-basin
+  "If point `yx` in `hmap` is in a basin (determined using `adj`), return a
+   list of points in the basin that are above `yx`."
+  [hmap yx adj]
+  (let [res (filter #(basin-continues? (get-in hmap yx)
+                                       (get-in hmap %))
+                    adj)]
+    (apply (partial clojure.set/union res)
+           (map #(set (find-basin hmap % (apply get-adj %))) res)
+           )))
+
+(->> (slurp "./in")
+     (clojure.string/split-lines)
+     (mapv vec)
+     (mapv (partial mapv #(- (int %) 48)))
+     (#(for [y (range 0 (count %))
+             x (range 0 (count (first %)))
+             :let [adj (get-adj y x)]
+             :when (basin-bottom? % [y x] adj)]
+         (inc (count (find-basin % [y x] adj)))))
+     (sort >)
+     (take 3)
+     (apply *)
+     (println)
+     )
+