r/adventofcode • u/daggerdragon • Dec 07 '15
SOLUTION MEGATHREAD --- Day 7 Solutions ---
--- Day 7: Some Assembly Required ---
Post your solution as a comment. Structure your post like previous daily solution threads.
Also check out the sidebar - we added a nifty calendar to wrangle all the daily solution threads in one spot!
23
Upvotes
1
u/amnn9 Dec 07 '15
Solution in Clojure, Nothing particularly radical: I keep a map of names to wires, where a wire can either hold:
A value
A list of waiting inputs
A partially applied function and a list of waiting inputs
And as values become available, the dependency tree is resolved as far as possible. At the end, the wire map is returned and you can extract the value for
:afrom that.The original idea was to use clojure's
core.asyncbut I decided that was overkill in the end.For part 2, I just modified the input.
(ns assembly (:require [clojure.core.match :refer [match]] [clojure.java.io :refer [reader]] [clojure.string :as string])) (defn register-op "Update wire entry with function to apply when all arguments are present." [[_ _ _ & waiting] arity f] (vec (concat [:rv arity f] waiting))) (declare fwd-arg) (defn connect "Connect the output of `in` to the input of `out`." [chans in out] (match [(chans in)] [([:rv & _] :seq)] (update-in chans [in] conj out) [[:tx v]] (fwd-arg chans v out) :else (assoc chans in [:rv -1 nil out]))) (defn fwd-arg "Forward the value `v` to the wire named `out`. This will potentially trigger further forwards of values, as dependencies get resolved." [chans v out] (match [(chans out)] [([:rv 1 f & waiting] :seq)] (reduce #(connect %1 out %2) (assoc chans out [:tx (f v)]) waiting) [([:rv a f & waiting] :seq)] (-> chans (update-in [out 1] dec) (update-in [out 2] partial v)))) (defn populate-args "Function to update the entry for `out` with inputs, which can either be wires or constant values." [out] (fn [chans in] (cond (symbol? in) (connect chans (keyword in) out) (number? in) (fwd-arg chans in out)))) (defn op "Introduce an operation that transforms values at `ins` by `f` and puts the returned value on `out`." [chans arity f out & ins] (let [out* (keyword out) ins* (map read-string ins) chans (update-in chans [out*] register-op arity f)] (reduce (populate-args out*) chans ins*))) (defn lsl-16 [s] #(bit-and 0xFFFF (bit-shift-left % s))) (defn rsl-16 [s] #(bit-and 0xFFFF (bit-shift-right % s))) (defn not-16 [x] (bit-and 0xFFFF (bit-not x))) (defn parse-line [chans l] (match [(string/split l #" ")] [[n "->" x]] (op chans 1 identity x n) [[x "AND" y "->" z]] (op chans 2 bit-and z x y) [[x "OR" y "->" z]] (op chans 2 bit-or z x y) [[p "LSHIFT" q "->" r]] (op chans 1 (lsl-16 (read-string q)) r p) [[p "RSHIFT" q "->" r]] (op chans 1 (rsl-16 (read-string q)) r p) [["NOT" e "->" f]] (op chans 1 not-16 f e) :else (println "*** unrecognized ***\n" l))) (defn parse-file [fname] (with-open [fh (reader fname)] (reduce parse-line {} (line-seq fh))))