start day23, todo: optimize part 2

This commit is contained in:
Adam Jeniski 2024-01-16 20:52:50 -05:00
parent bd784d925c
commit d0ef346755
2 changed files with 138 additions and 56 deletions

View File

@ -2,19 +2,20 @@
(:require [clj-http.client :as client] (:require [clj-http.client :as client]
[clojure.string :as string])) [clojure.string :as string]))
(def input-cache (atom {}))
(def cookie (str "session=" (slurp "session"))) (def cookie (str "session=" (slurp "session")))
(defn get-puzzle-input (defn get-puzzle-input
"retrieves and caches aoc input for 2023 given a day" "retrieves and caches aoc input for 2023 given a day"
[day] [day]
(or (@input-cache day) (let [file (java.io.File. (str "inputs/day" day ".txt"))]
(swap! input-cache assoc day (or (when (.exists file)
(-> (str "https://adventofcode.com/2023/day/" day "/input") (string/split-lines (slurp file)))
(let [data (-> (str "https://adventofcode.com/2023/day/" day "/input")
(client/get {:throw-entire-message? true (client/get {:throw-entire-message? true
:headers {"Cookie" cookie}}) :headers {"Cookie" cookie}})
:body :body)]
string/split-lines)))) (spit file data)
(string/split-lines data)))))
(defn re-seq-pos (defn re-seq-pos
"re-seq that produces a seq of {:start :end :group}" "re-seq that produces a seq of {:start :end :group}"
@ -40,32 +41,14 @@
~@body))) ~@body)))
(defmacro comp> (defmacro comp>
"comp, but fn-args are composed from left to right with currying "generates a closure that composes inputs with clojure.core/-> semantics"
previous result inserted as first element to next function application" [& forms]
[& ls] `(fn [v#] (-> v# ~@forms)))
(let [fs (map (fn [l]
(if (and (list? l)
(not= 'fn (first l)))
(let [[f & fargs] l]
`(fn [v#] (~f v# ~@fargs)))
l))
ls)
r (reverse fs)]
`(comp ~@r)))
(defmacro comp>> (defmacro comp>>
"comp, but fn-args are composed from left to right with currying "generates a closure that composes inputs with clojure.core/->> semantics"
previous result inserted as last element to next function application" [& forms]
[& ls] `(fn [v#] (->> v# ~@forms)))
(let [fs (map (fn [l]
(if (and (list? l)
(not= 'fn (first l)))
(let [[f & fargs] l]
`(fn [v#] (~f ~@fargs v#)))
l))
ls)
r (reverse fs)]
`(comp ~@r)))
(defmacro w-fn (defmacro w-fn
"wraps s-expr such as java static methods or macro calls "wraps s-expr such as java static methods or macro calls
@ -114,6 +97,7 @@
this function returns a vector where each value is the result of applying this function returns a vector where each value is the result of applying
an f from fs to the corresponding v from vs" an f from fs to the corresponding v from vs"
[& args] [& args]
;; TODO: add spec or manual validation for args
(let [n (/ (count args) 2)] (let [n (/ (count args) 2)]
(->> (zipmap (take n args) (->> (zipmap (take n args)
(take-last n args)) (take-last n args))
@ -126,17 +110,19 @@
this function returns a vector where each value is the result of applying this function returns a vector where each value is the result of applying
an f from fs to the corresponding value from v" an f from fs to the corresponding value from v"
;; TODO: add spec or manual validation for args
[& args] [& args]
(->> (zipmap (drop-last args) (->> (zipmap (drop-last args)
(last args)) (last args))
(mapv #((first %) (second %))))) (mapv #((first %) (second %)))))
(def p partial) (defmacro assert-all [& assertions]
`(do ~@(map (fn [assertion]
`(assert ~assertion))
assertions)))
(defmacro assert= [& abs] (defn partial< [f & args1]
`(do ~@(map (fn [[a b]] (fn [& args2] (apply f (concat args2 args1))))
`(assert (= ~a ~b)))
(partition 2 abs))))
(comment (comment
@ -152,18 +138,18 @@
(dec 2) (dec 2)
(+ (/ 1 2) (+ (/ 1 2)
(/ 1 2)))) (/ 1 2))))
(assert
(assert= (= ((comp> (+ 1) (/ 2) (abc 1) (inc) ;; currying / partial fn applicaiton
8 ((comp> (+ 1) (/ 2) (abc 1) (inc) ;; currying / partial fn applicaiton
inc ;; named fn inc ;; named fn
#(+ 1 %) (fn [v] (+ v 1))) ;; using lambdas #(+ 1 %) (fn [v] (+ v 1))) ;; using lambdas
5) 5)
8))
3 ((comp> (- 5) (- 2)) (assert (= ((comp> (- 5) (- 2))
10) 10)
3))
7 ((comp>> (- 5) (- 2)) (assert (= ((comp>> (- 5) (- 2))
10)) 10)
7))
(map (w-fn Long/parseLong) ["123" "456"]) (map (w-fn Long/parseLong) ["123" "456"])
input-cache input-cache
@ -172,14 +158,20 @@
((reducef + 0) [1 2]) ((reducef + 0) [1 2])
(let [v 20] (let [v 20]
(assert= ((comp> #(* % 3) #(+ % 2) #(* % 4)) (assert (= ((comp> #(* % 3) #(+ % 2) #(* % 4))
v) v)
((comp #(* % 4) #(+ % 2) #(* % 3)) ((comp #(* % 4) #(+ % 2) #(* % 3))
v))) v))))
(assert= (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 #(* % 2) #(+ % 5) 5 10)
(apply-each-v #(* % 2) #(+ % 5) [5 10])) (apply-each-v #(* % 2) #(+ % 5) [5 10])
[10 15]))
(log (+ 5 5) (log (+ 5 5)
(- 2 1)) (- 2 1))

90
2023/src/day23.clj Normal file
View File

@ -0,0 +1,90 @@
(ns day23
(:require
[clojure.string :as str]
[lonocloud.synthread.macros :refer :all]
[core :refer [get-puzzle-input]]))
; (def input (get-puzzle-input 23))
(def input (str/split-lines "#.#####################
#.......#########...###
#######.#########.#.###
###.....#.>.>.###.#.###
###v#####.#v#.###.#.###
###.>...#.#.#.....#...#
###v###.#.#.#########.#
###...#.#.#.......#...#
#####.#.#.#######.#.###
#.....#.#.#.......#...#
#.#####.#.#.#########v#
#.#...#...#...###...>.#
#.#.#v#######v###.###v#
#...#.>.#...>.>.#.###.#
#####v#.#.###v#.#.###.#
#.....#...#...#.#.#...#
#.#########.###.#.#.###
#...###...#...#...#.###
###.###.#.###v#####v###
#...#...#.#.>.>.#.>.###
#.###.###.#.###.#.#v###
#.....###...###...#...#
#####################.#"))
(def start [0 1])
(def end [(dec (count input))
(- (count (last input)) 2)])
(def char-map (->> input
(map-indexed (fn [row line]
(map-indexed (fn [col c]
[[row col] c])
line)))
(apply concat)
(into {})))
(def offsets [[0 1] [0 -1] [1 0] [-1 0]])
;; part 1
(->> (loop [q [{:loc start, :visited #{}}]
ans #{}]
(if (empty? q)
ans
(let [[{:keys [loc visited]}] q
visited' (conj visited loc)
[x y] loc]
(if (= end loc)
(recur (rest q) (conj ans (count visited)))
(recur (concat (rest q)
(-> []
(>for [o offsets]
(>let [[x' y' :as loc'] (mapv + loc o)]
(>when (and (not (visited loc'))
(or (= \. (char-map loc'))
(and (= \> (char-map loc')) (< y y'))
(and (= \< (char-map loc')) (> y y'))
(and (= \v (char-map loc')) (< x x'))
(and (= \^ (char-map loc')) (> x x'))))
(conj loc'))))
(>each (#(hash-map :loc % :visited visited')))))
ans)))))
(apply max))
;; part 2
(->> (loop [q [{:loc start, :visited #{}}]
ans #{}]
(if (empty? q)
ans
(let [[{:keys [loc visited]}] q
visited' (conj visited loc)]
(if (= end loc)
(recur (rest q) (conj ans (count visited)))
(recur (concat (rest q)
(-> []
(>for [o offsets]
(>let [[x' y' :as loc'] (mapv + loc o)]
(>when (and (not (visited loc'))
(#{ \. \> \< \v \^} (char-map loc')))
(conj loc'))))
(>each (#(hash-map :loc % :visited visited')))))
ans)))))
(apply max))