|
| 1 | +(ns y2024.d15 |
| 2 | + (:require |
| 3 | + [advent-of-code-clj.utils :as utils] |
| 4 | + [advent-of-code-clj.input :as input] |
| 5 | + [clojure.core.matrix :as mx])) |
| 6 | + |
| 7 | +(def test-data-small "######## |
| 8 | +#..O.O.# |
| 9 | +##@.O..# |
| 10 | +#...O..# |
| 11 | +#.#.O..# |
| 12 | +#...O..# |
| 13 | +#......# |
| 14 | +######## |
| 15 | +
|
| 16 | +<^^>>>vv<v>>v<<") |
| 17 | + |
| 18 | +(def test-data-large "########## |
| 19 | +#..O..O.O# |
| 20 | +#......O.# |
| 21 | +#.OO..O.O# |
| 22 | +#..O@..O.# |
| 23 | +#O#..O...# |
| 24 | +#O..O..O.# |
| 25 | +#.OO.O.OO# |
| 26 | +#....O...# |
| 27 | +########## |
| 28 | +
|
| 29 | +<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^ |
| 30 | +vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v |
| 31 | +><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv< |
| 32 | +<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^ |
| 33 | +^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^>< |
| 34 | +^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^ |
| 35 | +>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^ |
| 36 | +<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<> |
| 37 | +^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v> |
| 38 | +v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^") |
| 39 | + |
| 40 | +(def dir-vector {\< [0 -1] |
| 41 | + \v [1 0] |
| 42 | + \^ [-1 0] |
| 43 | + \> [0 1]}) |
| 44 | + |
| 45 | +(defn map-and-moves [input] |
| 46 | + (let [[game-map-str moves-str] (.split input "\n\n") |
| 47 | + game-matrix (utils/text->matrix game-map-str) |
| 48 | + coord-map (utils/coord-map-fixed game-matrix) |
| 49 | + grouped (group-by val coord-map)] |
| 50 | + {:game-state {:walls (->> (grouped \#) (map key) set) |
| 51 | + :boxes (->> (grouped \O) (map key) set) |
| 52 | + :pos (->> (grouped \@) first key)} |
| 53 | + :moves (keep dir-vector moves-str)})) |
| 54 | + |
| 55 | +(map-and-moves test-data-small) |
| 56 | + |
| 57 | +(defn push-boxes [walls boxes pos move] |
| 58 | + (let [path (seq (iteration (fn [x] (mapv + x move)) |
| 59 | + :initk pos |
| 60 | + :somef #(not (walls %)))) |
| 61 | + box-positions (map boxes path) |
| 62 | + boxes-to-move (set (take-while some? box-positions))] |
| 63 | + (if (= (count boxes-to-move) (count path)) |
| 64 | + nil ; No boxes could be moved |
| 65 | + (let [remaining-boxes (remove boxes-to-move boxes)] |
| 66 | + (into (set remaining-boxes) (map (fn [box] (mapv + box move)) boxes-to-move)))))) |
| 67 | + |
| 68 | +(defn print-board [{:keys [pos walls boxes]}] |
| 69 | + (let [dimensions [(inc (apply max (map first walls))) |
| 70 | + (inc (apply max (map second walls)))] |
| 71 | + walls (set walls) |
| 72 | + boxes (set boxes)] |
| 73 | + (mx/pm (mx/emap-indexed (fn [idx _] |
| 74 | + (cond |
| 75 | + (walls idx) \# |
| 76 | + (boxes idx) \O |
| 77 | + (= pos idx) \@)) (apply mx/new-matrix dimensions))))) |
| 78 | + |
| 79 | +(defn make-move [{:keys [pos walls boxes] :as game-state} move] |
| 80 | + (let [maybe-new-pos (mapv + pos move)] |
| 81 | + (cond |
| 82 | + (walls maybe-new-pos) game-state |
| 83 | + (boxes maybe-new-pos) (if-let [pushed-boxes (push-boxes walls boxes pos move)] |
| 84 | + (assoc game-state |
| 85 | + :pos maybe-new-pos |
| 86 | + :boxes pushed-boxes) |
| 87 | + game-state) |
| 88 | + :else (assoc game-state :pos maybe-new-pos)))) |
| 89 | + |
| 90 | +(defn gps-score [[y x :as _box]] |
| 91 | + (+ (* 100 y) x)) |
| 92 | + |
| 93 | +(defn part-1 [{:keys [game-state moves]}] |
| 94 | + (->> (reduce make-move game-state moves) |
| 95 | + (#(do |
| 96 | + (print-board %) |
| 97 | + %)) |
| 98 | + :boxes |
| 99 | + (map gps-score) |
| 100 | + (reduce +))) |
| 101 | + |
| 102 | +(part-1 (map-and-moves test-data-small)) |
| 103 | + |
| 104 | +(part-1 (map-and-moves test-data-large)) |
| 105 | + |
| 106 | +(delay (part-1 (map-and-moves (input/get-input 2024 15)))) |
0 commit comments