diff --git a/2024/src/day21.clj b/2024/src/day21.clj new file mode 100644 index 0000000..a3a086e --- /dev/null +++ b/2024/src/day21.clj @@ -0,0 +1,120 @@ +(ns day21 + (:require + [clojure.math :as math] + [clojure.string :as str] + [core :as c :refer :all] + [input-manager :as i] + [clojure.math.combinatorics :as combo])) + +(def input (i/get-input 2024 21)) + +(def pad-1-data [[nil \0 \A] + [\1 \2 \3] + [\4 \5 \6] + [\7 \8 \9]]) +(def pad-locs (-> pad-1-data map-to-coords (dissoc nil))) +(def pad-locs-by-coords (-> pad-1-data map-by-coords (dissoc [0 0]))) + +(def pad-2-data [[\< \v \>] + [nil \^ \A]]) +(def pad-locs-2 (-> pad-2-data map-to-coords (dissoc nil))) +(def pad-locs-2-by-coords (-> pad-2-data map-by-coords (dissoc [1 0]))) + +(def start (pad-locs \A)) +(def start-2 (pad-locs-2 \A)) + +(defn manhattan-distance [[row1 col1] [row2 col2]] + (+ (abs (- row1 row2)) + (abs (- col1 col2)))) + +(defn char->step-fn [c] + (fn [[row col]] + ({\> [row (inc col)] + \< [row (dec col)] + \^ [(inc row) col] + \v [(dec row) col]} c))) + +(defn progressive-steps [[row col :as pos] [target-row target-col] grid] + (->> [(when (> target-row row) + \^) + (when (< target-row row) + \v) + (when (> target-col col) + \>) + (when (< target-col col) + \<)] + (filter identity) + (filter #(grid ((char->step-fn %) pos))))) + +(defn shortest-walks + "returns list of all minimal length list keypresses (arrow chars)" + [start-pos target-pos grid] + (loop [n 0 + walks #{[start-pos []]}] + (or (and (or (->> walks + (map first) + (filter #(= % target-pos)) + not-empty) + (empty? walks)) + (->> walks + (map second) + (map #(conj % \A)))) + (->> walks + (mapcat (fn [[loc keystrokes]] + (let [steps (progressive-steps loc target-pos grid)] + (->> steps + (map #(vector ((char->step-fn %) loc) + (conj keystrokes %))))))) + set + (recur (inc n)))))) + +(defn generate-robot-subwalks [start-pos walk] + (->> walk + (map pad-locs-2) + ((juxt identity rest)) + (apply map vector) + (#(conj % [start-pos (pad-locs-2 (first walk))])) + (map #(shortest-walks (first %) (second %) pad-locs-2-by-coords)))) + +(defn generate-all-subwalk-options [depth code] + (loop [n 1 + acc (->> code + (reduce (fn [{:keys [pos w]} + el] + (let [pos' (pad-locs el) + walks (shortest-walks pos pos' pad-locs-by-coords)] + {:pos pos' + :w (conj w walks)})) + {:pos start + :w []}) + :w)] + (if (= n depth) + acc + (recur (inc n) + (n-map (* n 2) #(generate-robot-subwalks (pad-locs-2 \A) %) acc))))) + +(defn get-count-from-subwalks [depth all-walks] + (loop [n (dec depth) + acc (n-map (* depth 2) count all-walks)] + (if (neg? n) + acc + (recur (dec n) + (->> acc + (n-map (inc (* n 2)) + (partial apply min)) + (n-map (* n 2) + (partial reduce +))))))) + +(defn get-ans-for-code [depth code] + (let [c (->> (generate-all-subwalk-options depth code) + (get-count-from-subwalks depth)) + n (parse-long (->> code + drop-last + str/join))] + (* c n))) + +;; part 1 +(->> input + (map (partial get-ans-for-code 3)) + (reduce +) + println)