mirror of
https://github.com/Ajetski/advent-of-code.git
synced 2025-09-30 11:23:17 -09:00
193 lines
5.1 KiB
Clojure
193 lines
5.1 KiB
Clojure
(ns core
|
|
(:require [clj-http.client :as client]
|
|
[clojure.string :as string]))
|
|
|
|
(def cookie (str "session=" (slurp "session")))
|
|
|
|
(defn get-puzzle-input
|
|
"retrieves and caches aoc input for 2023 given a day"
|
|
[day]
|
|
(let [file (java.io.File. (str "inputs/day" day ".txt"))]
|
|
(or (when (.exists file)
|
|
(string/split-lines (slurp file)))
|
|
(let [data (-> (str "https://adventofcode.com/2023/day/" day "/input")
|
|
(client/get {:throw-entire-message? true
|
|
:headers {"Cookie" cookie}})
|
|
:body)]
|
|
(spit file data)
|
|
(string/split-lines data)))))
|
|
|
|
(defn re-seq-pos
|
|
"re-seq that produces a seq of {:start :end :group}"
|
|
[pattern string]
|
|
(let [m (re-matcher pattern string)]
|
|
((fn step []
|
|
(when (. m find)
|
|
(cons {:start (. m start) :end (. m end) :group (. m group)}
|
|
(lazy-seq (step))))))))
|
|
|
|
(defn split-spaces [s]
|
|
(string/split s #" "))
|
|
|
|
(defmacro let-dbg [arg-list & body]
|
|
(let [pairs (partition 2 arg-list)
|
|
definitions (->> pairs
|
|
(map (fn [[a b]]
|
|
`[~a (let [temp# ~b]
|
|
(println '~a "=" temp#)
|
|
temp#)]))
|
|
(apply concat))]
|
|
`(let [~@definitions]
|
|
~@body)))
|
|
|
|
(defmacro comp>
|
|
"generates a closure that composes inputs with clojure.core/-> semantics"
|
|
[& forms]
|
|
`(fn [v#] (-> v# ~@forms)))
|
|
|
|
(defmacro comp>>
|
|
"generates a closure that composes inputs with clojure.core/->> semantics"
|
|
[& forms]
|
|
`(fn [v#] (->> v# ~@forms)))
|
|
|
|
(defmacro w-fn
|
|
"wraps s-expr such as java static methods or macro calls
|
|
in a lambda so they can be passed as function objects"
|
|
[f] `(fn [v#] (~f v#)))
|
|
|
|
(defn mapvf
|
|
"returns a function that does mapv over f when called with a coll"
|
|
[f] #(mapv f %))
|
|
|
|
(defn reducef
|
|
"returns a function that reduces over f when called with a coll"
|
|
([f] #(reduce f %))
|
|
([f init] #(reduce f init %)))
|
|
|
|
(defmacro fn-m
|
|
"like fn but memoizes return values, including recursive calls"
|
|
[name arglist & body]
|
|
`(let [dp# (atom {})
|
|
f# (fn ~name ~arglist
|
|
(or (@dp# [~@arglist])
|
|
(let [res# (do ~@body)]
|
|
(swap! dp# assoc [~@arglist] res#)
|
|
res#)))]
|
|
f#))
|
|
|
|
(defmacro defn-m
|
|
"like defn but for a memoized fn, see ajet.core/fn-m"
|
|
[name arglist & body]
|
|
`(def ~name (fn-m ~name ~arglist ~@body)))
|
|
|
|
(defmacro log [& body]
|
|
(let [exprs# (map (fn [e#]
|
|
`(let [e-res# ~e#]
|
|
(println "expr:" '~e#)
|
|
(println "result: " e-res#)
|
|
e-res#)) body)]
|
|
`(do ~@exprs#
|
|
nil)))
|
|
|
|
(defn apply-each
|
|
"[& fs vs]
|
|
fs is a list of funcitons of length N
|
|
vs is a list of values of length N
|
|
|
|
this function returns a vector where each value is the result of applying
|
|
an f from fs to the corresponding v from vs"
|
|
[& args]
|
|
;; TODO: add spec or manual validation for args
|
|
(let [n (/ (count args) 2)]
|
|
(->> (zipmap (take n args)
|
|
(take-last n args))
|
|
(mapv #((first %) (second %))))))
|
|
|
|
(defn apply-each-v
|
|
"[& fs vs]
|
|
fs is a list of funcitons of length N
|
|
v is a vector of values of length N
|
|
|
|
this function returns a vector where each value is the result of applying
|
|
an f from fs to the corresponding value from v"
|
|
;; TODO: add spec or manual validation for args
|
|
[& args]
|
|
(->> (zipmap (drop-last args)
|
|
(last args))
|
|
(mapv #((first %) (second %)))))
|
|
|
|
(defmacro assert-all [& assertions]
|
|
`(do ~@(map (fn [assertion]
|
|
`(assert ~assertion))
|
|
assertions)))
|
|
|
|
(defn partial< [f & args1]
|
|
(fn [& args2] (apply f (concat args2 args1))))
|
|
|
|
(comment
|
|
|
|
(let-dbg [a 1
|
|
b (inc a)]
|
|
(+ a b))
|
|
|
|
(defn abc [a b]
|
|
(+ a b))
|
|
|
|
(assert (= 1
|
|
(inc 0)
|
|
(dec 2)
|
|
(+ (/ 1 2)
|
|
(/ 1 2))))
|
|
(assert
|
|
(= ((comp> (+ 1) (/ 2) (abc 1) (inc) ;; currying / partial fn applicaiton
|
|
inc ;; named fn
|
|
#(+ 1 %) (fn [v] (+ v 1))) ;; using lambdas
|
|
5)
|
|
8))
|
|
(assert (= ((comp> (- 5) (- 2))
|
|
10)
|
|
3))
|
|
(assert (= ((comp>> (- 5) (- 2))
|
|
10)
|
|
7))
|
|
|
|
(map (w-fn Long/parseLong) ["123" "456"])
|
|
input-cache
|
|
|
|
((mapvf #(* 2 %)) [1 2])
|
|
((reducef + 0) [1 2])
|
|
|
|
(let [v 20]
|
|
(assert (= ((comp> #(* % 3) #(+ % 2) #(* % 4))
|
|
v)
|
|
((comp #(* % 4) #(+ % 2) #(* % 3))
|
|
v))))
|
|
|
|
(assert-all
|
|
(=
|
|
(apply-each #(* % 2) #(+ % 5) 1 2)
|
|
(apply-each-v #(* % 2) #(+ % 5) [1 2])
|
|
[2 7])
|
|
(=
|
|
(apply-each #(* % 2) #(+ % 5) 5 10)
|
|
(apply-each-v #(* % 2) #(+ % 5) [5 10])
|
|
[10 15]))
|
|
|
|
(log (+ 5 5)
|
|
(- 2 1))
|
|
|
|
(defn-m fib [x]
|
|
(if (< x 2)
|
|
x
|
|
(+ (fib (- x 2))
|
|
(fib (dec x)))))
|
|
|
|
(map (w-fn log) [1 2])
|
|
|
|
;; 2000+ digit number generated in <16ms (leveraging polymorphism and big-int)
|
|
;; using a seemingly naive O(n!) implementation (leveraging defn-m, autocaching)
|
|
(time (fib 10000N))
|
|
|
|
;
|
|
)
|