-
Notifications
You must be signed in to change notification settings - Fork 0
/
05.clj
95 lines (76 loc) · 3.33 KB
/
05.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(ns sunny
(:require [clojure.string :as str]))
(defn split-commas [s] (str/split s #","))
(def test-program (->> (slurp "05.in")
(str/trim-newline)
(split-commas)
(map #(Integer/parseInt %))
(into [])))
(defn to-int [char] (Integer/parseInt (str char)))
(defn queue
([] (clojure.lang.PersistentQueue/EMPTY))
([coll]
(reduce conj clojure.lang.PersistentQueue/EMPTY coll)))
(defn opcode-details [opcode+modes]
(let [op-str (str opcode+modes)
opcode (Integer/parseInt (apply str (take-last 2 op-str)))
modes (into [] (map to-int (reverse (drop-last 2 op-str))))]
[opcode modes]))
(defn resolve-params [{:keys [intcode pointer]}]
(let [[opcode+modes & params] (subvec intcode pointer)
[opcode modes] (opcode-details opcode+modes)]
(map (fn [param mode] (if-not (= 1 mode) (nth intcode param) param))
params
(concat modes (repeat 0)))))
(def opcode->fn
{1 (fn sum [computer [param1 param2 store-at]]
(let [[param1* param2*] (resolve-params computer)]
(-> computer
(assoc-in [:intcode store-at] (+ param1* param2*))
(update :pointer (partial + 4)))))
2 (fn multiply [computer [param1 param2 store-at]]
(let [[param1* param2*] (resolve-params computer)]
(-> computer
(assoc-in [:intcode store-at] (* param1* param2*))
(update :pointer (partial + 4)))))
3 (fn store-input [computer [store-at]]
(-> computer
(assoc-in [:intcode store-at] (peek (:input computer)))
(update :input pop)
(update :pointer (partial + 2))))
4 (fn output [computer [read-from]]
(let [[read-from*] (resolve-params computer)]
(-> computer
(update :output #(conj % read-from*))
(update :pointer (partial + 2)))))
5 (fn jump-if-true [computer [param jump-to]]
(let [[param* jump-to*] (resolve-params computer)]
(-> computer
(update :pointer (if (not= 0 param*) (constantly jump-to*) (partial + 3))))))
6 (fn jump-if-false [computer [param jump-to]]
(let [[param* jump-to*] (resolve-params computer)]
(-> computer
(update :pointer (if (= 0 param*) (constantly jump-to*) (partial + 3))))))
7 (fn less-than [computer [param1 param2 store-at]]
(let [[param1* param2*] (resolve-params computer)]
(-> computer
(assoc-in [:intcode store-at] (if (< param1* param2*) 1 0))
(update :pointer (partial + 4)))))
8 (fn less-than [computer [param1 param2 store-at]]
(let [[param1* param2*] (resolve-params computer)]
(-> computer
(assoc-in [:intcode store-at] (if (= param1* param2*) 1 0))
(update :pointer (partial + 4)))))
99 (fn halt [computer _] computer)})
(defn run-until-halt [program input]
(loop [computer {:intcode program, :pointer 0, :input (queue input), :output []}]
(let [{:keys [intcode pointer]} computer
[opcode+modes & params] (subvec intcode pointer)
[opcode modes] (opcode-details opcode+modes)]
(if (= 99 opcode)
computer
(recur ((opcode->fn opcode) computer params))))))
;;; part 1
(run-until-halt test-program [1])
;;; part 2
(run-until-halt test-program [5])