(ns adventofcode2019.day07
[:require [adventofcode2019.lib :refer :all]
[clojure.string :as str]
- [clojure.math.combinatorics :as combo]])
-
-;; a slightly less awful hack
-(def phase-setting (atom [nil 0 nil nil nil nil
- nil nil nil nil nil nil]))
-(defn get-phase-setting []
- (let [input (first @phase-setting)]
- (swap! phase-setting subvec 1)
- input))
-(defn put-phase-setting [input]
- (swap! phase-setting assoc 1 input))
+ [clojure.math.combinatorics :as combo]
+ [clojure.core.async :as a]])
;; 0: function args&mem -> [mem (ctr -> ctr)]
;; 1: number of args
-(def operations {1 [(fn [a b c mem]
- [(assoc mem c (+ a b)) #(+ % 4)])
- 3]
- 2 [(fn [a b c mem]
- [(assoc mem c (* a b)) #(+ % 4)])
- 3]
- 3 [(fn [a mem]
- [(assoc mem a (get-phase-setting)) #(+ % 2)])
- 1]
- 4 [(fn [a mem]
- (put-phase-setting (mem a))
- [mem #(+ % 2)])
- 1]
- 5 [(fn [a b mem]
- [mem (if (not= a 0) (constantly b) #(+ % 3))])
- 2]
- 6 [(fn [a b mem]
- [mem (if (= a 0) (constantly b) #(+ % 3))])
- 2]
- 7 [(fn [a b c mem]
- [(assoc mem c (if (< a b) 1 0)) #(+ % 4)])
- 3]
- 8 [(fn [a b c mem]
- [(assoc mem c (if (= a b) 1 0)) #(+ % 4)])
- 3]})
-
-;; FIXME: sorry about the dropped forms i didn't want to fix it properly
-;; the problem is that flags don't apply to certain args for certain ops
-(defn decode-op [opcode]
+(defn decode-op [opcode in out]
(let [str-code (format "%05d" opcode)
[f3 f2 f1] (map #(= \1 %) (take 3 str-code))
op (parse-int (str/join (drop 3 str-code)))
- [operation arg-ct] (operations op)]
- [(case arg-ct
- 1 #(operation #_((if f1 identity %1) %2) %2 %1)
- 2 #(operation ((if f1 identity %1) %2)
- ((if f2 identity %1) %3) %1)
- 3 #(operation ((if f1 identity %1) %2)
- ((if f2 identity %1) %3)
- #_((if f3 identity %1) %4) %4 %1))
- arg-ct]))
+ with-flags (fn [[f ac]]
+ [(case ac
+ 1 #(f %2 %1)
+ 2 #(f ((if f1 identity %1) %2)
+ ((if f2 identity %1) %3) %1)
+ 3 #(f ((if f1 identity %1) %2)
+ ((if f2 identity %1) %3) %4 %1)) ac])]
+ (with-flags
+ (case op
+ 1 [(fn [a b c mem]
+ [(assoc mem c (+ a b)) #(+ % 4)])
+ 3]
+ 2 [(fn [a b c mem]
+ [(assoc mem c (* a b)) #(+ % 4)])
+ 3]
+ 3 [(fn [a mem]
+ [(assoc mem a (a/<!! in)) #(+ % 2)])
+ 1]
+ 4 [(fn [a mem]
+ (a/>!! out (mem a))
+ [mem #(+ % 2)])
+ 1]
+ 5 [(fn [a b mem]
+ [mem (if (not= a 0) (constantly b) #(+ % 3))])
+ 2]
+ 6 [(fn [a b mem]
+ [mem (if (= a 0) (constantly b) #(+ % 3))])
+ 2]
+ 7 [(fn [a b c mem]
+ [(assoc mem c (if (< a b) 1 0)) #(+ % 4)])
+ 3]
+ 8 [(fn [a b c mem]
+ [(assoc mem c (if (= a b) 1 0)) #(+ % 4)])
+ 3]))))
-(defn perform-operation [program counter]
+(defn perform-operation [program counter in out]
(let [opcode (program counter)
- [operation arg-ct] (decode-op opcode)
+ [operation arg-ct] (decode-op opcode in out)
args (->> (iterate inc counter)
(rest)
(take arg-ct)
(let [[program ctr-update] (apply operation program args)]
[program (ctr-update counter)])))
-(defn intcode [program]
- (loop [[program counter] [program 0]]
- (let [opcode (program counter)]
- (if (= opcode 99)
- program
- (recur (perform-operation program counter))))))
+(defn intcode
+ ([program]
+ (intcode program nil nil))
+ ([program in out]
+ (loop [[program counter] [program 0]]
+ (let [opcode (program counter)]
+ (if (= opcode 99)
+ program
+ (recur (perform-operation program counter in out)))))))
(defn day07 []
(let [input (mapv parse-int (get-list-from-file (input-file) #","))
- phase-settings (combo/permutations [0 1 2 3 4])
- all-outputs (for [[a b c d e] phase-settings]
- (do (reset! phase-setting [a 0 b nil c nil d nil e nil nil nil])
- (dotimes [_ 5] (intcode input))
- (last @phase-setting)))]
- (part1 (apply max all-outputs))
- #_(part2 )))
+ phase-settings-1 (combo/permutations [0 1 2 3 4])
+ phase-settings-2 (combo/permutations [5 6 7 8 9])
+ channels (->> #(a/chan 2)
+ (repeatedly 5)
+ (cycle))
+ all-outputs-1 (for [settings phase-settings-1]
+ (do (doall (map a/>!! channels settings))
+ (a/>!! (first channels) 0)
+ (doall (map intcode (repeat 5 input) channels (rest channels)))
+ (a/<!! (first channels))))
+ all-outputs-2 (for [settings phase-settings-2]
+ (do (doall (map a/>!! channels settings))
+ (a/>!! (first channels) 0)
+ (a/<!! (last (for [[prog in out]
+ (map vector (repeat 5 input) channels (rest channels))]
+ (a/thread
+ (intcode prog in out)))))
+ (a/<!! (first channels))))]
+ (part1 (apply max all-outputs-1))
+ (part2 (apply max all-outputs-2))))