Add untested day14pt1 (but it has tests!)
[adventofcode2019.git] / src / adventofcode2019 / day14.clj
diff --git a/src/adventofcode2019/day14.clj b/src/adventofcode2019/day14.clj
new file mode 100644 (file)
index 0000000..e0e9b26
--- /dev/null
@@ -0,0 +1,58 @@
+(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]])
+
+(defn parse-reaction [reaction-text]
+  (let [parse-chemical (fn [text]
+                         (let [[ct chem] (str/split (str/trim 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))}))
+
+(defn make-graph [input]
+  (reduce (partial merge-with merge)
+          (map (comp normalize-reaction parse-reaction) input)))
+
+(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 day14 []
+  (let [graphed (make-graph (get-list-from-file (input-file)))]
+    (part1 (find-lowest-exchange-rate graphed "FUEL" "ORE"))
+    #_(part2)))