Fix day9pt1 and add correct day9pt2
[adventofcode2019.git] / src / adventofcode2019 / intcode.clj
CommitLineData
c0464c3a
JK
1(ns adventofcode2019.intcode
2 [:require [adventofcode2019.lib :refer :all]])
3
4;; 0: function args&mem -> [mem (ctr -> ctr)]
5;; 1: number of args
6(defn- decode-op [opcode]
7 (let [str-code (format "%05d" opcode)
8 flags (reverse (take 3 str-code))
9 op (vec (drop 3 str-code))
10 apply-flag (fn [flag arg]
11 (case flag
cce51437
JK
12 \0 (fn ([S] (get-in S [:memory arg]))
13 ([_ _] arg))
c0464c3a 14 \1 (constantly arg)
cce51437
JK
15 \2 (fn ([S] (get-in S [:memory (+ arg (:relctr S))]))
16 ([S _] (+ arg (:relctr S))))))
c0464c3a
JK
17 with-flags (fn [f]
18 (fn [S & args]
19 (apply f S (map apply-flag flags args))))]
20 (with-flags
21 (case op
22 [\0 \1] (fn [S a b c] ; ADD
23 (-> S
cce51437 24 (assoc-in [:memory (c S 0)] (+' (a S) (b S)))
c0464c3a
JK
25 (update :ctr + 4)))
26 [\0 \2] (fn [S a b c] ; MULT
27 (-> S
cce51437 28 (assoc-in [:memory (c S 0)] (*' (a S) (b S)))
c0464c3a
JK
29 (update :ctr + 4)))
30 [\0 \3] (fn [S a _ _] ; IN
31 (-> S
cce51437 32 (assoc-in [:memory (a S 0)] (first (:input S)))
c0464c3a
JK
33 (update :input subvec 1)
34 (update :ctr + 2)))
35 [\0 \4] (fn [S a _ _] ; OUT
36 (-> S
cce51437 37 (update :output conj (get-in S [:memory (a S 0)]))
c0464c3a
JK
38 (update :ctr + 2)))
39 [\0 \5] (fn [S a b _] ; BNEQ
40 (update S :ctr (if (not= (a S) 0) (constantly (b S)) #(+ % 3))))
41 [\0 \6] (fn [S a b _] ; BEQ
42 (update S :ctr (if (= (a S) 0) (constantly (b S)) #(+ % 3))))
43 [\0 \7] (fn [S a b c] ; SLT
44 (-> S
cce51437 45 (assoc-in [:memory (c S 0)] (if (< (a S) (b S)) 1 0))
c0464c3a
JK
46 (update :ctr + 4)))
47 [\0 \8] (fn [S a b c] ; SEQ
48 (-> S
cce51437 49 (assoc-in [:memory (c S 0)] (if (= (a S) (b S)) 1 0))
c0464c3a
JK
50 (update :ctr + 4)))
51 [\0 \9] (fn [S a _ _] ; SREL
52 (-> S
53 (update :relctr + (a S))
54 (update :ctr + 2)))
55 [\9 \9] (fn [S _ _ _] ; EXIT
56 (assoc S :exit 1))))))
57
58(defn- perform-operation [{:keys [memory ctr] :as state}]
59 (let [operation (decode-op (memory ctr))
60 args (map memory [(+ 1 ctr) (+ 2 ctr) (+ 3 ctr)])]
61 (apply operation state args)))
62
63(defn build-state
64 ([program]
65 (let [memory (into {} (map-indexed #(vector %1 %2) program))]
66 {:memory memory :ctr 0 :input [] :output [] :relctr 0}))
67 ([program settings]
68 (merge (build-state program) settings)))
69
70(defn intcode [{:as state :keys [memory output]}]
71 (cond ; quit if :exit, step and return state if :step, else loop
72 (get state :exit) {:memory memory :output output}
73 (get state :step) (perform-operation state)
74 :else (recur (perform-operation state))))