Add untested day14pt1 (but it has tests!)
authorJack Kinsey <kinsey_john@bah.com>
Wed, 18 Dec 2019 23:01:58 +0000 (18:01 -0500)
committerJack Kinsey <kinsey_john@bah.com>
Wed, 18 Dec 2019 23:01:58 +0000 (18:01 -0500)
src/adventofcode2019/core.clj
src/adventofcode2019/day14.clj [new file with mode: 0644]
test/adventofcode2019/day14_test.clj [new file with mode: 0644]

index ca8684be0c2f8b0daecc24c44455ffc771463a9c..3e6794e99f47314795111e282ea4e6061524ba0d 100644 (file)
@@ -1,7 +1,7 @@
 (ns adventofcode2019.core
     [:require (adventofcode2019 day01 day02 day03 day04 day05 
                                 day06 day07 day08 day09 day10 
-                                day11 day12 day13)])
+                                day11 day12 day13 day14)])
 
 (defn -main 
   ([]
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)))
diff --git a/test/adventofcode2019/day14_test.clj b/test/adventofcode2019/day14_test.clj
new file mode 100644 (file)
index 0000000..1a6bd86
--- /dev/null
@@ -0,0 +1,37 @@
+(ns adventofcode2019.day14-test
+  (:require [clojure.test :refer :all]
+            [adventofcode2019.day14 :refer :all]))
+
+(deftest check-make-graph
+  (is (= (make-graph ["3 ORE => 2 ABC" 
+                      "3 ABC => 1 FUEL"])
+         {"ABC"  {{"ORE" 3/2} 1}
+          "FUEL" {{"ABC" 3}   1}})))
+
+(deftest simple-exchange
+  (is (= 3 (find-lowest-exchange-rate {"FUEL" {{"ORE" 1, "ABC" 2, "DEF" 3} 1 
+                                               {"ORE" 3} 1 
+                                               {"GHI" 5/2} 1}} 
+                                      "FUEL" "ORE"))))
+
+(deftest trading-up
+  (is (= 6 (find-lowest-exchange-rate (make-graph ["3 ORE => 2 ABC"
+                                                   "3 ABC => 1 FUEL"])
+                                      "FUEL" "ORE"))))
+
+(deftest complicated-exchange
+  (is (= 2 (find-lowest-exchange-rate (make-graph ["3 ORE => 2 ABC"
+                                                   "3 ABC => 1 FUEL"
+                                                   "2 ORE => 1 CDE"
+                                                   "1 CDE => 1 FUEL"])
+                                      "FUEL" "ORE"))))
+
+(deftest very-tricky-exchange
+  (is (= 3 (find-lowest-exchange-rate (make-graph ["3 ORE => 2 ABC"
+                                                   "3 ABC => 1 FUEL"
+                                                   "4 ORE => 1 CDE"
+                                                   "1 CDE => 1 FUEL"
+                                                   "3 ORE => 2 FGH"
+                                                   "1 FGH => 1 IJK"
+                                                   "1 IJK => 1 FUEL"])
+                                      "FUEL" "ORE"))))