2023 day 14 in Clojure

This commit is contained in:
aru 2023-12-19 15:41:08 +01:00
parent 76c20b36c5
commit 302c187e9f
2 changed files with 210 additions and 0 deletions

200
2023/clojure/day14.clj Normal file
View File

@ -0,0 +1,200 @@
(ns day14
(:require [clojure.string :as s]
[aoc]))
(defn parse-input [input]
(s/split-lines input))
;; (defn column-load [col]
;; (let [mw (count col)]
;; (->> (map-indexed vector col)
;; (remove (fn [[idx e]] (= e \.)))
;; (reduce (fn [[sum weight] [idx e]]
;; (case e
;; \# [sum (dec (- mw idx))]
;; \O [(+ sum weight) (dec weight)]
;; \. [sum weight]))
;; [0 mw])
;; first)))
;; (defn expand [width [round cube]]
;; (for [x (range 0 width)]
;; (cond
;; (round x) \O
;; (cube x) \#
;; :else \.)))
;; (defn column-tilt [col]
;; (let [mw (count col)]
;; (->> (map-indexed vector col)
;; (remove (fn [[idx e]] (= e \.)))
;; (reduce (fn [[round cube pos] [idx e]]
;; (case e
;; \# [round (conj cube idx) (inc idx)]
;; \O [(conj round pos) cube (inc pos)]
;; \. [round cube pos]))
;; [#{} #{} 0])
;; (take 2)
;; (expand mw))))
;; (defn tilt-west [col]
;; (map column-tilt col))
;; (defn tilt-east [col]
;; (->> col
;; (map reverse)
;; tilt-west
;; (map reverse)))
;; (defn tilt-north [col]
;; (->> col
;; aoc/transpose
;; tilt-west
;; aoc/transpose))
;; (defn tilt-south [col]
;; (->> col
;; aoc/transpose
;; tilt-east
;; aoc/transpose))
;; (defn display [col]
;; (doseq [l col]
;; (println (apply str l)))
;; (println))
;; (defn tilt-around [col]
;; (-> col tilt-north tilt-west tilt-south tilt-east))
;; (defn crude-cycle-detect [col]
;; (reduce (fn [[cache state] cur]
;; (let [cached (cache state)]
;; (if cached
;; (do
;; (println (str "Cache hit " cur " = " (cache state)))
;; (reduced [cached (- cur cached) cache]))
;; [(assoc cache state cur) (tilt-around state)])))
;; [{} col]
;; (range 1 1001)))
;; (defn tilt-n-times [n col]
;; (reduce (fn [acc _] (tilt-around acc)) col (range n)))
;; (defn score-grid [col]
;; (reduce + (map column-load (aoc/transpose (tilt-north col)))))
;; (defn part2 [input]
;; (let [[start period cache] (crude-cycle-detect input)
;; rcache (into {} (map (fn [[k v]] [v k]) cache))
;; n (+ start (mod (- 1000000000 start) period))]
;; (first (filter (fn [i] (= 64 (score-grid (rcache i)))) (range 1 (count rcache))))))
;; (defn part2-bf [input]
;; ;; (let [[start period cache] (crude-cycle-detect input)
;; (let [[cache state] (crude-cycle-detect input)
;; rcache (into {} (map (fn [[k v]] [v k]) cache))]
;; (println (count rcache))
;; (first (filter (fn [i] (= 64 (reduce + (map column-load (aoc/transpose (rcache i)))))) (range 0 10)))))
;; (let [parsed (parse-input (slurp "../data/14/example"))]
;; (println (part2 parsed)))
;; ;; (par)
;; ;; (println (reduce + (map column-load (tilt-n-times (+ 141 82) parsed)))))
;; ;; (crude-cycle-detect parsed))
;; ;; (reduce + (map column-load (aoc/transpose (tilt-north parsed)))))
(defn to-grid [col]
(let [mx (count col)
my (count (first col))
points (for [x (range mx)
y (range my)
:let [e (nth (nth col x) y)]]
[[x y] e])]
{:dimensions [mx my] :points (into {} points)}))
(defn pt+ [[x1 y1] [x2 y2]]
[(+ x1 x2) (+ y1 y2)])
(defn direction-range [{[mx my] :dimensions p :points} direction [x y]]
(case direction
"north" (reverse (for [x (range x)] [x y]))
"south" (for [x (range (inc x) mx)] [x y])
"west" (reverse (for [y (range y)] [x y]))
"east" (for [y (range (inc y) my)] [x y])))
(defn direction-add [direction]
(case direction
"north" #(pt+ %1 [(- %2) 0])
"south" #(pt+ %1 [%2 0])
"west" #(pt+ %1 [0 (- %2)])
"east" #(pt+ %1 [0 %2])))
(defn move [g direction p]
(let [dir-range (direction-range g direction p)
dir-f (direction-add direction)
path (map (fn [p] (get-in g [:points p])) dir-range)
remaining (take-while #(not= % \#) path)
offset (count (filter #(= % \.) remaining))]
(dir-f p offset)))
(defn find-rocks [{points :points}]
(->> points
(filter (fn [[_ v]] (= v \O)))
(map first)))
(defn update-grid [g rocks moved]
(as-> g g
(reduce (fn [acc cur] (assoc-in acc [:points cur] \.)) g rocks)
(reduce (fn [acc cur] (assoc-in acc [:points cur] \O)) g moved)))
(defn move-rocks [g direction]
(let [rocks (find-rocks g)
moved (map (partial move g direction) rocks)]
(update-grid g rocks moved)))
(defn display-grid [{[mx my] :dimensions p :points}]
(dotimes [x mx]
(dotimes [y my]
(let [c (p [x y])]
(print (or c \.))))
(println)))
(defn move-cycle [g]
(-> g
(move-rocks "north")
(move-rocks "west")
(move-rocks "south")
(move-rocks "east")))
(defn rock-weight [{[mx _] :dimensions :as g}]
(->> (find-rocks g)
(map (fn [[x y]] (- mx x)))
(reduce + 0)))
(defn part1 [input]
(-> input
(move-rocks "north")
rock-weight))
(defn crude-cycle-detect [{p :points :as g}]
(reduce (fn [[cache state] cur]
(let [cached (cache state)]
(if cached
(reduced [cached (- cur cached) cache])
(let [calculated (move-cycle state)]
[(assoc cache state cur) (move-cycle state)]))))
[{} g]
(range)))
(defn part2 [g]
(let [[start period cache] (crude-cycle-detect g)
rcache (into {} (map (fn [[k v]] [v k]) cache))
n (+ start (mod (- 1000000000 start) period))]
(rock-weight (rcache n))))
;; ;; Invoke with clj -M -m day14 input
(defn -main [file & args]
(let [i (parse-input (slurp file))
g (to-grid i)]
(println (str "Part 1: " (part1 g)))
(println (str "Part 2: " (part2 g)))))

10
2023/data/14/example Normal file
View File

@ -0,0 +1,10 @@
O....#....
O.OO#....#
.....##...
OO.#O....O
.O.....O#.
O.#..O.#.#
..O..#O..O
.......O..
#....###..
#OO..#....