Rework day14pt1
[adventofcode2019.git] / src / adventofcode2019 / day14.clj
index e0e9b26402f7ae9ad1fa8153341bb20151409efa..e2aae3e11000ebd9e14f8920caec7d10234c9fea 100644 (file)
@@ -1,10 +1,7 @@
 (ns adventofcode2019.day14
-    [:require [adventofcode2019.lib :refer :all]
-              [adventofcode2019.intcode :as i]
-              [clojure.string :as str]
-              [clojure.set :as set]
-              [clojure.core.match :refer [match]]
-              [clojure.math.combinatorics :as combo]])
+  [:require [adventofcode2019.lib :refer :all]
+            [clojure.string :as str]
+            [clojure.core.match :refer [match]]])
 
 (defn parse-reaction [reaction-text]
   (let [parse-chemical (fn [text]
                            {chem (parse-int ct)}))
         [inputs output] (str/split reaction-text #"=>")
         [[out-chem out-ct]] (seq (parse-chemical output))]
-    {out-chem {(reduce merge {} (map parse-chemical (str/split inputs #","))) out-ct}}))
-
-(defn normalize-reaction [reaction]
-  (let [[output] (keys reaction)
-        arrows (reaction output)
-        inputs (keys arrows)
-        normalize-arrow (fn [[akey aval]]
-                          {(reduce-kv (fn [m k v]
-                                        (assoc m k (rationalize (/ v aval)))) 
-                                      {} akey) 1})]
-    {output (reduce merge {} (map normalize-arrow arrows))}))
+    {out-chem [(reduce merge {} (map parse-chemical (str/split inputs #","))) out-ct]}))
 
 (defn make-graph [input]
   (reduce (partial merge-with merge)
-          (map (comp normalize-reaction parse-reaction) input)))
+          (map parse-reaction input)))
+
+(defn reduce-reaction [graph producing consuming]
+  (let [[inputs moles] (graph producing)
+        in-chems (keys inputs)
+        replace-term (fn [chem]
+                       (if (or (= chem consuming)
+                               (neg? (second (graph chem))))
+                         {chem (inputs chem)}
+                         (let [ch-req (inputs chem)
+                               [ch-in ch-mo] (graph chem)
+                               conversion (int (Math/ceil (/ ch-req ch-mo)))]
+                           (assoc (mmap (partial * conversion) ch-in)
+                                  chem (- ch-req (* ch-mo conversion))))))
+        check-reduced (fn [[ch ct]] (and (not= ch consuming) (pos? ct)))
+        reduced-inputs (reduce (partial merge-with +)
+                               (map replace-term in-chems))
+        new-graph (assoc graph producing [reduced-inputs moles])]
+    (if (some check-reduced reduced-inputs)
+      (recur new-graph producing consuming)
+      new-graph)))
 
-(defn find-lowest-exchange-rate [graph start end]
-  (let [reactions (graph start)
-        input-lists (keys reactions)
-        input-chems (mapv keys input-lists)
-        trade (fn [recv exch]
-                (let [rx (if (ratio? exch) (numerator exch) exch)
-                      xc (if (ratio? exch) (denominator exch) 1)
-                      units (int (Math/ceil (/ recv xc)))]
-                  (* units rx)))
-        find-terminal #(match [%]
-                              [({end v} :only [end])] v
-                              :else nil)
-        calculate-er (fn [[chem ct]] 
-                       (trade ct (find-lowest-exchange-rate graph chem end)))
-        reaction-er #(reduce + (map calculate-er %))]
-    (if (some #{[end]} input-chems)
-      (->> input-lists
-           (map find-terminal)
-           (remove nil?)
-           (reduce min))
-      (->> input-lists
-           (map reaction-er)
-           (reduce min)))))
+(defn find-lowest-exchange-rate [graph producing consuming]
+  (get-in (reduce-reaction graph producing consuming)
+          [producing 0 consuming]))
 
 (defn day14 []
   (let [graphed (make-graph (get-list-from-file (input-file)))]