From 8d43e37df99f280377bed90284d6ac2428334804 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 30 Nov 2022 19:55:31 -0500 Subject: move 2021 days to folder; update README --- README.md | 12 ++- day1/part1.clj | 15 ---- day1/part2.clj | 15 ---- day10/part1.clj | 22 ----- day10/part2.clj | 24 ------ day10/partboth.clj | 34 -------- day11/part1.clj | 41 --------- day11/part2.clj | 42 --------- day12/part1.clj | 27 ------ day12/part2.clj | 50 ----------- day13/part1.clj | 30 ------- day13/part2.clj | 33 -------- day13/partboth.clj | 49 ----------- day14/part1.clj | 27 ------ day14/part2.clj | 38 --------- day15/part1.clj | 30 ------- day15/part2.clj | 41 --------- day16/part1.clj | 67 --------------- day16/part2.cpp | 131 ----------------------------- day17/part3.clj | 59 ------------- day17/partboth.clj | 54 ------------ day18/partboth.clj | 95 --------------------- day19/partboth.clj | 98 --------------------- day2/part1.clj | 26 ------ day2/part2.clj | 27 ------ day20/partboth.clj | 43 ---------- day21/part1.clj | 22 ----- day21/part2.clj | 37 -------- day22/part1.clj | 25 ------ day22/part2.clj | 60 ------------- day23/part1-done-by-hand | 0 day23/part2.clj | 90 -------------------- day24/checker.clj | 47 ----------- day24/partboth.clj | 41 --------- day24/solved-by-hand-with-help.md | 4 - day25/part1.clj | 40 --------- day3/part1.clj | 25 ------ day3/part2.clj | 36 -------- day4/part1.clj | 70 --------------- day4/part2.clj | 70 --------------- day5/part1.clj | 75 ----------------- day5/part2.clj | 83 ------------------ day6/consteval.cpp | 32 ------- day6/part1.clj | 20 ----- day6/part2.clj | 25 ------ day7/maxima.mac | 10 --- day7/part1.clj | 18 ---- day7/part2.clj | 20 ----- day8/part1.clj | 15 ---- day8/part2.clj | 66 --------------- day9/part1.clj | 21 ----- day9/part2.clj | 45 ---------- year2021/day1/part1.clj | 15 ++++ year2021/day1/part2.clj | 15 ++++ year2021/day10/part1.clj | 22 +++++ year2021/day10/part2.clj | 24 ++++++ year2021/day10/partboth.clj | 34 ++++++++ year2021/day11/part1.clj | 41 +++++++++ year2021/day11/part2.clj | 42 +++++++++ year2021/day12/part1.clj | 27 ++++++ year2021/day12/part2.clj | 50 +++++++++++ year2021/day13/part1.clj | 30 +++++++ year2021/day13/part2.clj | 33 ++++++++ year2021/day13/partboth.clj | 49 +++++++++++ year2021/day14/part1.clj | 27 ++++++ year2021/day14/part2.clj | 38 +++++++++ year2021/day15/part1.clj | 30 +++++++ year2021/day15/part2.clj | 41 +++++++++ year2021/day16/part1.clj | 67 +++++++++++++++ year2021/day16/part2.cpp | 131 +++++++++++++++++++++++++++++ year2021/day17/part3.clj | 59 +++++++++++++ year2021/day17/partboth.clj | 54 ++++++++++++ year2021/day18/partboth.clj | 95 +++++++++++++++++++++ year2021/day19/partboth.clj | 98 +++++++++++++++++++++ year2021/day2/part1.clj | 26 ++++++ year2021/day2/part2.clj | 27 ++++++ year2021/day20/partboth.clj | 43 ++++++++++ year2021/day21/part1.clj | 22 +++++ year2021/day21/part2.clj | 37 ++++++++ year2021/day22/part1.clj | 25 ++++++ year2021/day22/part2.clj | 60 +++++++++++++ year2021/day23/part1-done-by-hand | 0 year2021/day23/part2.clj | 90 ++++++++++++++++++++ year2021/day24/checker.clj | 47 +++++++++++ year2021/day24/partboth.clj | 41 +++++++++ year2021/day24/solved-by-hand-with-help.md | 4 + year2021/day25/part1.clj | 40 +++++++++ year2021/day3/part1.clj | 25 ++++++ year2021/day3/part2.clj | 36 ++++++++ year2021/day4/part1.clj | 70 +++++++++++++++ year2021/day4/part2.clj | 70 +++++++++++++++ year2021/day5/part1.clj | 75 +++++++++++++++++ year2021/day5/part2.clj | 83 ++++++++++++++++++ year2021/day6/consteval.cpp | 32 +++++++ year2021/day6/part1.clj | 20 +++++ year2021/day6/part2.clj | 25 ++++++ year2021/day7/maxima.mac | 10 +++ year2021/day7/part1.clj | 18 ++++ year2021/day7/part2.clj | 20 +++++ year2021/day8/part1.clj | 15 ++++ year2021/day8/part2.clj | 66 +++++++++++++++ year2021/day9/part1.clj | 21 +++++ year2021/day9/part2.clj | 45 ++++++++++ 103 files changed, 2125 insertions(+), 2117 deletions(-) delete mode 100644 day1/part1.clj delete mode 100644 day1/part2.clj delete mode 100644 day10/part1.clj delete mode 100644 day10/part2.clj delete mode 100644 day10/partboth.clj delete mode 100644 day11/part1.clj delete mode 100644 day11/part2.clj delete mode 100644 day12/part1.clj delete mode 100644 day12/part2.clj delete mode 100644 day13/part1.clj delete mode 100644 day13/part2.clj delete mode 100644 day13/partboth.clj delete mode 100644 day14/part1.clj delete mode 100644 day14/part2.clj delete mode 100644 day15/part1.clj delete mode 100644 day15/part2.clj delete mode 100644 day16/part1.clj delete mode 100644 day16/part2.cpp delete mode 100644 day17/part3.clj delete mode 100644 day17/partboth.clj delete mode 100644 day18/partboth.clj delete mode 100644 day19/partboth.clj delete mode 100644 day2/part1.clj delete mode 100644 day2/part2.clj delete mode 100644 day20/partboth.clj delete mode 100644 day21/part1.clj delete mode 100644 day21/part2.clj delete mode 100644 day22/part1.clj delete mode 100644 day22/part2.clj delete mode 100644 day23/part1-done-by-hand delete mode 100644 day23/part2.clj delete mode 100644 day24/checker.clj delete mode 100644 day24/partboth.clj delete mode 100644 day24/solved-by-hand-with-help.md delete mode 100644 day25/part1.clj delete mode 100644 day3/part1.clj delete mode 100644 day3/part2.clj delete mode 100644 day4/part1.clj delete mode 100644 day4/part2.clj delete mode 100644 day5/part1.clj delete mode 100644 day5/part2.clj delete mode 100644 day6/consteval.cpp delete mode 100644 day6/part1.clj delete mode 100644 day6/part2.clj delete mode 100644 day7/maxima.mac delete mode 100644 day7/part1.clj delete mode 100644 day7/part2.clj delete mode 100644 day8/part1.clj delete mode 100644 day8/part2.clj delete mode 100644 day9/part1.clj delete mode 100644 day9/part2.clj create mode 100644 year2021/day1/part1.clj create mode 100644 year2021/day1/part2.clj create mode 100644 year2021/day10/part1.clj create mode 100644 year2021/day10/part2.clj create mode 100644 year2021/day10/partboth.clj create mode 100644 year2021/day11/part1.clj create mode 100644 year2021/day11/part2.clj create mode 100644 year2021/day12/part1.clj create mode 100644 year2021/day12/part2.clj create mode 100644 year2021/day13/part1.clj create mode 100644 year2021/day13/part2.clj create mode 100644 year2021/day13/partboth.clj create mode 100644 year2021/day14/part1.clj create mode 100644 year2021/day14/part2.clj create mode 100644 year2021/day15/part1.clj create mode 100644 year2021/day15/part2.clj create mode 100644 year2021/day16/part1.clj create mode 100644 year2021/day16/part2.cpp create mode 100644 year2021/day17/part3.clj create mode 100644 year2021/day17/partboth.clj create mode 100644 year2021/day18/partboth.clj create mode 100644 year2021/day19/partboth.clj create mode 100644 year2021/day2/part1.clj create mode 100644 year2021/day2/part2.clj create mode 100644 year2021/day20/partboth.clj create mode 100644 year2021/day21/part1.clj create mode 100644 year2021/day21/part2.clj create mode 100644 year2021/day22/part1.clj create mode 100644 year2021/day22/part2.clj create mode 100644 year2021/day23/part1-done-by-hand create mode 100644 year2021/day23/part2.clj create mode 100644 year2021/day24/checker.clj create mode 100644 year2021/day24/partboth.clj create mode 100644 year2021/day24/solved-by-hand-with-help.md create mode 100644 year2021/day25/part1.clj create mode 100644 year2021/day3/part1.clj create mode 100644 year2021/day3/part2.clj create mode 100644 year2021/day4/part1.clj create mode 100644 year2021/day4/part2.clj create mode 100644 year2021/day5/part1.clj create mode 100644 year2021/day5/part2.clj create mode 100644 year2021/day6/consteval.cpp create mode 100644 year2021/day6/part1.clj create mode 100644 year2021/day6/part2.clj create mode 100644 year2021/day7/maxima.mac create mode 100644 year2021/day7/part1.clj create mode 100644 year2021/day7/part2.clj create mode 100644 year2021/day8/part1.clj create mode 100644 year2021/day8/part2.clj create mode 100644 year2021/day9/part1.clj create mode 100644 year2021/day9/part2.clj diff --git a/README.md b/README.md index e0c4e58..9edc6dd 100644 --- 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 index 1c2c756..0000000 --- a/day1/part1.clj +++ /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 index e496c7d..0000000 --- a/day1/part2.clj +++ /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 index 60ed1e6..0000000 --- a/day10/part1.clj +++ /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 index 4dfaf3b..0000000 --- a/day10/part2.clj +++ /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 index 78080d9..0000000 --- a/day10/partboth.clj +++ /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 index 5113fd4..0000000 --- a/day11/part1.clj +++ /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 index 4c4663c..0000000 --- a/day11/part2.clj +++ /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 index cdd4a43..0000000 --- a/day12/part1.clj +++ /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 index 06b2bcd..0000000 --- a/day12/part2.clj +++ /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 index c3f08d4..0000000 --- a/day13/part1.clj +++ /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 index 6db6555..0000000 --- a/day13/part2.clj +++ /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 index c24980d..0000000 --- a/day13/partboth.clj +++ /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 index de03bda..0000000 --- a/day14/part1.clj +++ /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 index f5de5fe..0000000 --- a/day14/part2.clj +++ /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 index 7838e34..0000000 --- a/day15/part1.clj +++ /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 index a422ed0..0000000 --- a/day15/part2.clj +++ /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 index 2358e59..0000000 --- a/day16/part1.clj +++ /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 index 5a02df9..0000000 --- a/day16/part2.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -static const std::map 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 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 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 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 index ae51260..0000000 --- a/day17/part3.clj +++ /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 index c585bf9..0000000 --- a/day17/partboth.clj +++ /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 index 83fc42c..0000000 --- a/day18/partboth.clj +++ /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 index 48f1a9c..0000000 --- a/day19/partboth.clj +++ /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 index e4e9d49..0000000 --- a/day2/part1.clj +++ /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 index 9487a49..0000000 --- a/day2/part2.clj +++ /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 index 33a4d4f..0000000 --- a/day20/partboth.clj +++ /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 index 174f5a1..0000000 --- a/day21/part1.clj +++ /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 index 0042aaa..0000000 --- a/day21/part2.clj +++ /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 index bffc1a9..0000000 --- a/day22/part1.clj +++ /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 index c5d2803..0000000 --- a/day22/part2.clj +++ /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 index e69de29..0000000 diff --git a/day23/part2.clj b/day23/part2.clj deleted file mode 100644 index adbefc1..0000000 --- a/day23/part2.clj +++ /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 index 4874f62..0000000 --- a/day24/checker.clj +++ /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 index 9548ec3..0000000 --- a/day24/partboth.clj +++ /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 index 1ddf03e..0000000 --- a/day24/solved-by-hand-with-help.md +++ /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 index df2947c..0000000 --- a/day25/part1.clj +++ /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 index 3fe888e..0000000 --- a/day3/part1.clj +++ /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 index 00e656f..0000000 --- a/day3/part2.clj +++ /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 index b9fcceb..0000000 --- a/day4/part1.clj +++ /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 index 516e83c..0000000 --- a/day4/part2.clj +++ /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 index 95d04ba..0000000 --- a/day5/part1.clj +++ /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 index d324618..0000000 --- a/day5/part2.clj +++ /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 index f46da89..0000000 --- a/day6/consteval.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include -#include - -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 index 70293f7..0000000 --- a/day6/part1.clj +++ /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 index ad6fe91..0000000 --- a/day6/part2.clj +++ /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 index a1c2d18..0000000 --- a/day7/maxima.mac +++ /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 index f08e5b4..0000000 --- a/day7/part1.clj +++ /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 index b96b55d..0000000 --- a/day7/part2.clj +++ /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 index fe06fdf..0000000 --- a/day8/part1.clj +++ /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 index 1ee3c08..0000000 --- a/day8/part2.clj +++ /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 index 7bd8e23..0000000 --- a/day9/part1.clj +++ /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 index 3030c4e..0000000 --- a/day9/part2.clj +++ /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 index 0000000..1c2c756 --- /dev/null +++ b/year2021/day1/part1.clj @@ -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 index 0000000..e496c7d --- /dev/null +++ b/year2021/day1/part2.clj @@ -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 index 0000000..60ed1e6 --- /dev/null +++ b/year2021/day10/part1.clj @@ -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 index 0000000..4dfaf3b --- /dev/null +++ b/year2021/day10/part2.clj @@ -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 index 0000000..78080d9 --- /dev/null +++ b/year2021/day10/partboth.clj @@ -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 index 0000000..5113fd4 --- /dev/null +++ b/year2021/day11/part1.clj @@ -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 index 0000000..4c4663c --- /dev/null +++ b/year2021/day11/part2.clj @@ -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 index 0000000..cdd4a43 --- /dev/null +++ b/year2021/day12/part1.clj @@ -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 index 0000000..06b2bcd --- /dev/null +++ b/year2021/day12/part2.clj @@ -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 index 0000000..c3f08d4 --- /dev/null +++ b/year2021/day13/part1.clj @@ -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 index 0000000..6db6555 --- /dev/null +++ b/year2021/day13/part2.clj @@ -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 index 0000000..c24980d --- /dev/null +++ b/year2021/day13/partboth.clj @@ -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 index 0000000..de03bda --- /dev/null +++ b/year2021/day14/part1.clj @@ -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 index 0000000..f5de5fe --- /dev/null +++ b/year2021/day14/part2.clj @@ -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 index 0000000..7838e34 --- /dev/null +++ b/year2021/day15/part1.clj @@ -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 index 0000000..a422ed0 --- /dev/null +++ b/year2021/day15/part2.clj @@ -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 index 0000000..2358e59 --- /dev/null +++ b/year2021/day16/part1.clj @@ -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 index 0000000..5a02df9 --- /dev/null +++ b/year2021/day16/part2.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static const std::map 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 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 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 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 index 0000000..ae51260 --- /dev/null +++ b/year2021/day17/part3.clj @@ -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 index 0000000..c585bf9 --- /dev/null +++ b/year2021/day17/partboth.clj @@ -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 index 0000000..83fc42c --- /dev/null +++ b/year2021/day18/partboth.clj @@ -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 index 0000000..48f1a9c --- /dev/null +++ b/year2021/day19/partboth.clj @@ -0,0 +1,98 @@ +(require '[clojure.core.reducers :as r]) +(require 'clojure.string) + +(def orientation-vectors + [[[1 0 0] [0 1 0] [0 0 1]] + [[1 0 0] [0 0 -1] [0 1 0]] + [[1 0 0] [0 -1 0] [0 0 -1]] + [[1 0 0] [0 0 1] [0 -1 0]] + [[-1 0 0] [0 -1 0] [0 0 1]] + [[-1 0 0] [0 0 -1] [0 -1 0]] + [[-1 0 0] [0 1 0] [0 0 -1]] + [[-1 0 0] [0 0 1] [0 1 0]] + [[0 0 -1] [1 0 0] [0 -1 0]] + [[0 1 0] [1 0 0] [0 0 -1]] + [[0 0 1] [1 0 0] [0 1 0]] + [[0 -1 0] [1 0 0] [0 0 1]] + [[0 0 1] [-1 0 0] [0 -1 0]] + [[0 1 0] [-1 0 0] [0 0 1]] + [[0 0 -1] [-1 0 0] [0 1 0]] + [[0 -1 0] [-1 0 0] [0 0 -1]] + [[0 -1 0] [0 0 -1] [1 0 0]] + [[0 0 1] [0 -1 0] [1 0 0]] + [[0 1 0] [0 0 1] [1 0 0]] + [[0 0 -1] [0 1 0] [1 0 0]] + [[0 0 1] [0 1 0] [-1 0 0]] + [[0 -1 0] [0 0 1] [-1 0 0]] + [[0 0 -1] [0 -1 0] [-1 0 0]] + [[0 1 0] [0 0 -1] [-1 0 0]]]) + +(defn build-scanner-reports + "Splits slurped, split-line'd input by scanner." + [input-lines] + (loop [scanners [] rem-input input-lines] + (if (empty? rem-input) + scanners + (let [[this nxt] (split-with (comp not empty?) rem-input)] + (recur (->> (rest this) + (map #(read-string (clojure.string/join ["[" % "]"]))) + (conj scanners)) + (rest nxt)))))) + +(defn point-add [[a b c] [d e f]] [(+ a d) (+ b e) (+ c f)]) + +(defn orient [[x y z] [[a b c] [d e f] [g h i]]] + [(+ (* x a) (* y d) (* z g)) (+ (* x b) (* y e) (* z h)) (+ (* x c) (* y f) (* z i))]) + +(defn scanner-orientation [report or-index] + (map #(orient (map - %) (get orientation-vectors or-index)) report)) + +(defn scanner-orientations + "Builds list of scanner reports adjusted for all possible orientations." + [report] + (for [or-vec orientation-vectors] + (map #(orient (map - %) or-vec) report))) + +(defn scanner-build-potential-links + "Builds a list for each s2 orientation that contains lists of each s1 point + added to the corresponding s2 point." + [s1 s2] + (for [s2-or (scanner-orientations s2)] + (for [i (range 0 (count s1))] + (for [j (range 0 (count s2-or))] + (point-add (nth s1 i) (nth s2-or j)))))) + +(defn scanner-find-connection + "Attempt to determine if s1 and s2 are linked through common beacons." + [s1 s2] + (loop [potential-links (as-> (scanner-build-potential-links s1 s2) $ + (for [i (range 0 (count $))] [i (nth $ i)]) + (into [] $))] + (when-let [[orientation link] (first potential-links)] + (if-let [match (first (drop-while #(< (val %) 12) (frequencies (reduce concat link))))] + [orientation (key match)] + (recur (rest potential-links)))))) + +(defn scanner-merge + "Merges the report of linked scanner s2 into scanner s1." + [s1 s2 s2-or s2-coord] + (vec (into (set s1) (map #(point-add s2-coord (map - %)) (scanner-orientation s2 s2-or))))) + +(let [[beacon-count scanner-coords] + (loop [new-reps (->> (slurp "./in") clojure.string/split-lines build-scanner-reports) + sc-coords '([0 0 0]) + next-reps (rest new-reps)] + (if-let [next-rep (first next-reps)] + (if-let [[found-or found-coord] (scanner-find-connection (first new-reps) next-rep)] + (let [new-base (scanner-merge (first new-reps) next-rep found-or found-coord) + newest-reps (->> (assoc new-reps 0 new-base) (filterv (partial not= next-rep)))] + (println "found" found-coord) + (recur newest-reps (conj sc-coords found-coord) (rest newest-reps))) + (recur new-reps sc-coords (rest next-reps))) + [(count (first new-reps)) sc-coords]))] + (println "Part 1:" beacon-count) + (println "Part 2:" + (apply max + (for [p1 scanner-coords p2 scanner-coords :when (not= p1 p2)] + (apply + (map #(Math/abs %) (point-add (map - p1) p2))))))) + diff --git a/year2021/day2/part1.clj b/year2021/day2/part1.clj new file mode 100644 index 0000000..e4e9d49 --- /dev/null +++ b/year2021/day2/part1.clj @@ -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 index 0000000..9487a49 --- /dev/null +++ b/year2021/day2/part2.clj @@ -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 index 0000000..33a4d4f --- /dev/null +++ b/year2021/day20/partboth.clj @@ -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 index 0000000..174f5a1 --- /dev/null +++ b/year2021/day21/part1.clj @@ -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 index 0000000..0042aaa --- /dev/null +++ b/year2021/day21/part2.clj @@ -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 index 0000000..bffc1a9 --- /dev/null +++ b/year2021/day22/part1.clj @@ -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 index 0000000..c5d2803 --- /dev/null +++ b/year2021/day22/part2.clj @@ -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 index 0000000..e69de29 diff --git a/year2021/day23/part2.clj b/year2021/day23/part2.clj new file mode 100644 index 0000000..adbefc1 --- /dev/null +++ b/year2021/day23/part2.clj @@ -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 index 0000000..4874f62 --- /dev/null +++ b/year2021/day24/checker.clj @@ -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 index 0000000..9548ec3 --- /dev/null +++ b/year2021/day24/partboth.clj @@ -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 index 0000000..1ddf03e --- /dev/null +++ b/year2021/day24/solved-by-hand-with-help.md @@ -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 index 0000000..df2947c --- /dev/null +++ b/year2021/day25/part1.clj @@ -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 index 0000000..3fe888e --- /dev/null +++ b/year2021/day3/part1.clj @@ -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 index 0000000..00e656f --- /dev/null +++ b/year2021/day3/part2.clj @@ -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 index 0000000..b9fcceb --- /dev/null +++ b/year2021/day4/part1.clj @@ -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 index 0000000..516e83c --- /dev/null +++ b/year2021/day4/part2.clj @@ -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 index 0000000..95d04ba --- /dev/null +++ b/year2021/day5/part1.clj @@ -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 index 0000000..d324618 --- /dev/null +++ b/year2021/day5/part2.clj @@ -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 index 0000000..f46da89 --- /dev/null +++ b/year2021/day6/consteval.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +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 index 0000000..70293f7 --- /dev/null +++ b/year2021/day6/part1.clj @@ -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 index 0000000..ad6fe91 --- /dev/null +++ b/year2021/day6/part2.clj @@ -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 index 0000000..a1c2d18 --- /dev/null +++ b/year2021/day7/maxima.mac @@ -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 index 0000000..f08e5b4 --- /dev/null +++ b/year2021/day7/part1.clj @@ -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 index 0000000..b96b55d --- /dev/null +++ b/year2021/day7/part2.clj @@ -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 index 0000000..fe06fdf --- /dev/null +++ b/year2021/day8/part1.clj @@ -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 index 0000000..1ee3c08 --- /dev/null +++ b/year2021/day8/part2.clj @@ -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 index 0000000..7bd8e23 --- /dev/null +++ b/year2021/day9/part1.clj @@ -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 index 0000000..3030c4e --- /dev/null +++ b/year2021/day9/part2.clj @@ -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) + ) + -- cgit v1.2.3