|
| 1 | +(ns y2023.d4 |
| 2 | + (:require [clojure.math :as math] |
| 3 | + [clojure.set :as set] |
| 4 | + [clojure.string :as str] |
| 5 | + [hyperfiddle.rcf :refer [tests]] |
| 6 | + [utils :as u])) |
| 7 | + |
| 8 | +(def dummy-input |
| 9 | + ["Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53" |
| 10 | + "Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19" |
| 11 | + "Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1" |
| 12 | + "Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83" |
| 13 | + "Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36" |
| 14 | + "Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11"]) |
| 15 | +(def input (u/input)) |
| 16 | + |
| 17 | +; --- input parsing --- |
| 18 | + |
| 19 | +(defn- parse-card [s] |
| 20 | + (let [[_ winning nums] (re-find #"Card +\d+: +(.*) +\| +(.*)" s) |
| 21 | + f (fn [s] (->> (str/split s #" +") (map parse-long) set))] |
| 22 | + {:winning (f winning) |
| 23 | + :nums (f nums)})) |
| 24 | + |
| 25 | +(defn parse [input] |
| 26 | + (mapv parse-card input)) |
| 27 | + |
| 28 | +; --- solving --- |
| 29 | + |
| 30 | +(defn points [{:keys [winning nums] :as _card}] |
| 31 | + (int (math/pow 2.0 (dec (count (set/intersection winning nums)))))) |
| 32 | + |
| 33 | +(defn copy-cards |
| 34 | + "Reduce over cards, accumulating copies. Return total copies." |
| 35 | + [cards] |
| 36 | + (->> (map-indexed vector cards) ; generate an index |
| 37 | + (reduce (fn [copies [i {:keys [winning nums]}]] |
| 38 | + (let [n (count (set/intersection winning nums))] |
| 39 | + ; make <number of copies of this card> copies of (i+1)th -> (i+n)th cards |
| 40 | + (merge-with + copies (zipmap (range (inc i) (+ (inc i) n)) |
| 41 | + (repeat (get copies i)))))) |
| 42 | + ; init copies to {0 1, 1 1, 2 1, ...} map |
| 43 | + ; one entry for each card |
| 44 | + (zipmap (range (count cards)) (repeat 1))) |
| 45 | + (vals) |
| 46 | + (apply +))) |
| 47 | + |
| 48 | +(defn solve [input & {:keys [part]}] |
| 49 | + (cond->> (parse input) |
| 50 | + (= 1 part) (map points) |
| 51 | + (= 1 part) (apply +) |
| 52 | + (= 2 part) (copy-cards))) |
| 53 | + |
| 54 | +(tests |
| 55 | + (solve dummy-input :part 1) := 13 |
| 56 | + (solve dummy-input :part 2) := 30 |
| 57 | + ) |
| 58 | + |
| 59 | +(comment |
| 60 | + (solve input :part 1) ; => 21105 |
| 61 | + (solve input :part 2) ; => 5329815 |
| 62 | + ) |
0 commit comments