aoc

ref: master

2020/src/aoc/day07.clj


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
(ns aoc.day07
  (:require [clojure.java.io :as io]))

(def example
  "light red bags contain 1 bright white bag, 2 muted yellow bags.
dark orange bags contain 3 bright white bags, 4 muted yellow bags.
bright white bags contain 1 shiny gold bag.
muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.
shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.
dark olive bags contain 3 faded blue bags, 4 dotted black bags.
vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.
faded blue bags contain no other bags.
dotted black bags contain no other bags.")

(def rule-pattern #"(\d+) (\w+ \w+)")
(def mine "shiny gold")

(defn parse-sub [s]
  (let [[_ number color] (re-find rule-pattern s)]
    {:color color
     :number (read-string number)}))

(defn parse-contents [s]
  (when-not (clojure.string/starts-with? s "no")
    (let [rules (clojure.string/split s #", ")]
      (map parse-sub rules))))

(defn parse-rule [s]
  (let [[bag contents] (clojure.string/split s #" contain ")
        [shade color _] (clojure.string/split bag #" ")
        contents (parse-contents contents)]
    {:color (str shade " " color)
     :contents contents}))

(defn graph [rules]
  (reduce (fn [acc {:keys [color contents]}]
            (reduce (fn [acc content]
                      (update acc (:color content) conj {:color color
                                                         :number (:number content)}))
                    acc contents))
          {} rules))

(defn graph2 [rules]
  (reduce (fn [acc {:keys [color contents]}]
            (reduce (fn [acc2 content]
                      (update acc2 color conj content))
                    acc contents))
          {} rules))

(defn get-parents [graph color]
  (get graph color))

(defn fold [g]
  (loop [r (into #{} (->> (get-parents g mine)
                          (map :color)))]
    (let [r2 (reduce (fn [acc color]
                        (into acc
                              (->> 
                                (get-parents g color)
                                (map :color))))
                      r r)]
      (if (= r r2)
        r
        (recur r2)))))

(defn count-contents [g c]
  (let [contents (get-parents g c)]
    (if (seq contents)
      (reduce
       (fn [acc {:keys [color number]}]
         (+ acc (* number (count-contents g color))))
       1
       contents)
      1)))

;; ---

(defn read-input []
  (->> (slurp (io/resource "input07.txt"))
       (clojure.string/split-lines)))

(defn compute-1 [input]
  (let [rules (map parse-rule input)
        g (graph rules)]
    (count (fold g))))

(defn compute-2 [input]
  (let [rules (map parse-rule input)
        g (graph2 rules)]
    (dec
      (count-contents g mine))))

(defn main []
  (let [input (read-input)]
    (println (compute-1 input))
    (println (compute-2 input))))

(main)