Skip to content

Commit 738c80a

Browse files
committed
day09: Sensor Boost
1 parent c241935 commit 738c80a

File tree

4 files changed

+138
-40
lines changed

4 files changed

+138
-40
lines changed

resources/day09_input.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,3,1,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,0,34,1006,1101,0,689,1022,1102,27,1,1018,1102,1,38,1010,1102,1,31,1012,1101,20,0,1015,1102,1,791,1026,1102,0,1,1020,1101,24,0,1000,1101,0,682,1023,1101,788,0,1027,1101,0,37,1005,1102,21,1,1011,1102,1,28,1002,1101,0,529,1024,1101,39,0,1017,1102,30,1,1013,1101,0,23,1003,1102,524,1,1025,1101,32,0,1007,1102,25,1,1008,1101,29,0,1001,1101,33,0,1016,1101,410,0,1029,1101,419,0,1028,1101,22,0,1014,1102,26,1,1019,1102,1,35,1009,1102,36,1,1004,1102,1,1,1021,109,11,2107,22,-8,63,1005,63,199,4,187,1106,0,203,1001,64,1,64,1002,64,2,64,109,2,21108,40,40,-2,1005,1011,221,4,209,1106,0,225,1001,64,1,64,1002,64,2,64,109,13,21102,41,1,-7,1008,1019,41,63,1005,63,251,4,231,1001,64,1,64,1106,0,251,1002,64,2,64,109,-19,1202,1,1,63,1008,63,26,63,1005,63,271,1105,1,277,4,257,1001,64,1,64,1002,64,2,64,109,7,2101,0,-6,63,1008,63,24,63,1005,63,297,1106,0,303,4,283,1001,64,1,64,1002,64,2,64,109,7,1205,-1,315,1105,1,321,4,309,1001,64,1,64,1002,64,2,64,109,-11,21107,42,41,0,1005,1010,341,1001,64,1,64,1106,0,343,4,327,1002,64,2,64,109,-8,1207,6,24,63,1005,63,363,1001,64,1,64,1106,0,365,4,349,1002,64,2,64,109,11,1206,8,381,1001,64,1,64,1106,0,383,4,371,1002,64,2,64,109,4,1205,4,401,4,389,1001,64,1,64,1105,1,401,1002,64,2,64,109,14,2106,0,-3,4,407,1001,64,1,64,1106,0,419,1002,64,2,64,109,-33,1202,3,1,63,1008,63,29,63,1005,63,445,4,425,1001,64,1,64,1105,1,445,1002,64,2,64,109,-5,2102,1,7,63,1008,63,25,63,1005,63,465,1105,1,471,4,451,1001,64,1,64,1002,64,2,64,109,11,21107,43,44,7,1005,1011,489,4,477,1105,1,493,1001,64,1,64,1002,64,2,64,109,-3,1208,8,35,63,1005,63,511,4,499,1105,1,515,1001,64,1,64,1002,64,2,64,109,25,2105,1,-2,4,521,1106,0,533,1001,64,1,64,1002,64,2,64,109,-8,21108,44,47,-8,1005,1010,549,1106,0,555,4,539,1001,64,1,64,1002,64,2,64,109,-19,1207,7,35,63,1005,63,577,4,561,1001,64,1,64,1106,0,577,1002,64,2,64,109,2,2108,32,0,63,1005,63,597,1001,64,1,64,1106,0,599,4,583,1002,64,2,64,109,13,2101,0,-7,63,1008,63,32,63,1005,63,625,4,605,1001,64,1,64,1105,1,625,1002,64,2,64,109,-13,2107,24,2,63,1005,63,645,1001,64,1,64,1106,0,647,4,631,1002,64,2,64,109,18,21101,45,0,-4,1008,1015,43,63,1005,63,671,1001,64,1,64,1105,1,673,4,653,1002,64,2,64,109,-6,2105,1,10,1001,64,1,64,1105,1,691,4,679,1002,64,2,64,109,1,1208,-6,23,63,1005,63,707,1105,1,713,4,697,1001,64,1,64,1002,64,2,64,109,-2,1206,8,731,4,719,1001,64,1,64,1106,0,731,1002,64,2,64,109,-7,21102,46,1,5,1008,1010,43,63,1005,63,751,1106,0,757,4,737,1001,64,1,64,1002,64,2,64,109,-9,2108,24,4,63,1005,63,779,4,763,1001,64,1,64,1106,0,779,1002,64,2,64,109,38,2106,0,-7,1106,0,797,4,785,1001,64,1,64,1002,64,2,64,109,-27,2102,1,-6,63,1008,63,29,63,1005,63,819,4,803,1105,1,823,1001,64,1,64,1002,64,2,64,109,1,21101,47,0,7,1008,1015,47,63,1005,63,845,4,829,1105,1,849,1001,64,1,64,1002,64,2,64,109,-11,1201,5,0,63,1008,63,31,63,1005,63,869,1106,0,875,4,855,1001,64,1,64,1002,64,2,64,109,5,1201,4,0,63,1008,63,34,63,1005,63,901,4,881,1001,64,1,64,1105,1,901,4,64,99,21102,27,1,1,21101,915,0,0,1105,1,922,21201,1,58905,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1106,0,922,22101,0,1,-1,21201,-2,-3,1,21102,1,957,0,1106,0,922,22201,1,-1,-2,1106,0,968,22102,1,-2,-2,109,-3,2106,0,0
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
(ns clj-adventofcode-2019.day09
2+
(:require
3+
[clj-adventofcode-2019.intcode :as intcode]
4+
[clojure.math.numeric-tower :as math]))
5+
6+
;--- Day 9: Sensor Boost ---
7+
;You've just said goodbye to the rebooted rover and left Mars when you receive a faint distress signal coming from the asteroid belt. It must be the Ceres monitoring station!
8+
;
9+
;In order to lock on to the signal, you'll need to boost your sensors. The Elves send up the latest BOOST program - Basic Operation Of System Test.
10+
;
11+
;While BOOST (your puzzle input) is capable of boosting your sensors, for tenuous safety reasons, it refuses to do so until the computer it runs on passes some checks to demonstrate it is a complete Intcode computer.
12+
;
13+
;Your existing Intcode computer is missing one key feature: it needs support for parameters in relative mode.
14+
;
15+
;Parameters in mode 2, relative mode, behave very similarly to parameters in position mode: the parameter is interpreted as a position. Like position mode, parameters in relative mode can be read from or written to.
16+
;
17+
;The important difference is that relative mode parameters don't count from address 0. Instead, they count from a value called the relative base. The relative base starts at 0.
18+
;
19+
;The address a relative mode parameter refers to is itself plus the current relative base. When the relative base is 0, relative mode parameters and position mode parameters with the same value refer to the same address.
20+
;
21+
;For example, given a relative base of 50, a relative mode parameter of -7 refers to memory address 50 + -7 = 43.
22+
;
23+
;The relative base is modified with the relative base offset instruction:
24+
;
25+
;Opcode 9 adjusts the relative base by the value of its only parameter. The relative base increases (or decreases, if the value is negative) by the value of the parameter.
26+
;For example, if the relative base is 2000, then after the instruction 109,19, the relative base would be 2019. If the next instruction were 204,-34, then the value at address 1985 would be output.
27+
;
28+
;Your Intcode computer will also need a few other capabilities:
29+
;
30+
;The computer's available memory should be much larger than the initial program. Memory beyond the initial program starts with the value 0 and can be read or written like any other memory. (It is invalid to try to access memory at a negative address, though.)
31+
;The computer should have support for large numbers. Some instructions near the beginning of the BOOST program will verify this capability.
32+
;Here are some example programs that use these features:
33+
;
34+
;109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99 takes no input and produces a copy of itself as output.
35+
;1102,34915192,34915192,7,4,7,99,0 should output a 16-digit number.
36+
;104,1125899906842624,99 should output the large number in the middle.
37+
;The BOOST program will ask for a single input; run it in test mode by providing it the value 1. It will perform a series of checks on each opcode, output any opcodes (and the associated parameter modes) that seem to be functioning incorrectly, and finally output a BOOST keycode.
38+
;
39+
;Once your Intcode computer is fully functional, the BOOST program should report no malfunctioning opcodes when run in test mode; it should only output a single value, the BOOST keycode. What BOOST keycode does it produce?
40+
41+
(def the-program (intcode/load-program-from-resource "day09_input.txt"))
42+
43+
(def part1-result (:output (intcode/initialize-and-run the-program [1])))
44+
45+
46+
;--- Part Two ---
47+
;You now have a complete Intcode computer.
48+
;
49+
;Finally, you can lock on to the Ceres distress signal! You just need to boost your sensors using the BOOST program.
50+
;
51+
;The program runs in sensor boost mode by providing the input instruction the value 2. Once run, it will boost the sensors automatically, but it might take a few seconds to complete the operation on slower hardware. In sensor boost mode, the program will output a single value: the coordinates of the distress signal.
52+
53+
(def part2-result (:output (intcode/initialize-and-run the-program [2])))
54+
Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
(ns clj-adventofcode-2019.intcode
22
(:require
33
[clojure.math.numeric-tower :as math]
4-
))
4+
[clojure.java.io :as io]))
55

66

77
(def operations {1 :add
@@ -13,19 +13,21 @@
1313
6 :jump-if-false
1414
7 :less-than
1515
8 :eq
16+
9 :adjust-rel-base
1617
})
1718

1819
(def number-of-params
1920
{
20-
:add 3
21-
:mul 3
22-
:in 1
23-
:out 1
24-
:exit 0
25-
:jump-if-true 2
26-
:jump-if-false 2
27-
:less-than 3
28-
:eq 3
21+
:add 3
22+
:mul 3
23+
:in 1
24+
:out 1
25+
:exit 0
26+
:jump-if-true 2
27+
:jump-if-false 2
28+
:less-than 3
29+
:eq 3
30+
:adjust-rel-base 1
2931
})
3032

3133

@@ -35,22 +37,39 @@
3537

3638

3739
(defn parameter-mode-for-parameter [opcode param-num]
38-
(get {0 :position 1 :immediate}
40+
(get {0 :position 1 :immediate 2 :relative}
3941
(mod (quot opcode
4042
(* 10 (math/expt 10 param-num))) 10))
4143
)
4244

45+
(defn load-from-address [address state]
46+
(if (< address (count (:program state)))
47+
(nth (:program state) address)
48+
(get (:extra-memory state) address 0)))
49+
50+
51+
(defn save-to-address [address value state]
52+
(if (< address (count (:program state)))
53+
(assoc-in state [:program address] value)
54+
(assoc-in state [:extra-memory address] value)))
4355

44-
(defn get-param [param-number opcode program position]
45-
(let [param-mode (parameter-mode-for-parameter opcode param-number)]
56+
57+
(defn get-address [param-number opcode state]
58+
(let [position (:position state)
59+
param-mode (parameter-mode-for-parameter opcode param-number)]
4660
(case param-mode
47-
:immediate (nth program (+ position param-number))
48-
:position (nth program (nth program (+ position param-number)))
49-
:else (throw (AssertionError. "Wrong param."))
50-
)
61+
:immediate (+ position param-number)
62+
:position (load-from-address (+ position param-number) state)
63+
:relative (+ (:rel-base state) (load-from-address (+ position param-number) state))
64+
:else (throw (AssertionError. "Wrong param.")))
5165
))
5266

5367

68+
(defn get-param [param-number opcode state]
69+
(load-from-address (get-address param-number opcode state) state))
70+
71+
72+
5473
(defn initialize-program
5574
([program] (initialize-program program []))
5675
([program input]
@@ -61,68 +80,68 @@
6180
:output []
6281
:extra-memory {}
6382
:status :running
83+
:rel-base 0
6484
}))
6585

6686

6787
(defn exec-next-operation [state]
68-
(let [
69-
program (:program state)
70-
position (:position state)
71-
opcode (nth (:program state) (:position state))
88+
(let [opcode (nth (:program state) (:position state))
7289
operation (opcode-to-operation opcode)
7390
num-of-params (number-of-params operation)
7491
next-position (inc (+ (:position state) num-of-params))
7592
]
7693
(case operation
77-
(:add :mul) (let [first-param (get-param 1 opcode program position)
78-
second-param (get-param 2 opcode program position)
94+
(:add :mul) (let [first-param (get-param 1 opcode state)
95+
second-param (get-param 2 opcode state)
7996
calculation-fn (cond
8097
(= operation :add) +
8198
(= operation :mul) *
8299
:else (throw (AssertionError. "Wrong operation code.")))
83100
result (calculation-fn first-param second-param)
84-
destination-addr (nth program (+ position 3))]
85-
(assoc state
86-
:program (assoc program destination-addr result)
101+
destination-addr (get-address 3 opcode state)]
102+
(assoc (save-to-address destination-addr result state)
87103
:position next-position
88104
))
89105
:in (let [
90106
input (:input state)
91-
first-param (nth program (inc position))]
107+
first-param (get-address 1 opcode state)]
92108
(if (empty? input)
93109
(assoc state :status :waiting-for-input)
94-
(assoc state
95-
:program (assoc program first-param (first input))
110+
(assoc (save-to-address first-param (first input) state)
96111
:input (rest input)
97112
:status :running
98113
:position next-position
99114
)))
100-
:out (let [first-param (get-param 1 opcode program position)]
115+
:out (let [first-param (get-param 1 opcode state)]
101116
(assoc state
102117
:output (conj (:output state) first-param)
103118
:position next-position))
104119
:exit (assoc state :status :exited)
105120

106121
(:jump-if-true :jump-if-false)
107-
(let [first-param (get-param 1 opcode program position)
108-
second-param (get-param 2 opcode program position)]
122+
(let [first-param (get-param 1 opcode state)
123+
second-param (get-param 2 opcode state)]
109124
(if (or
110125
(and (= operation :jump-if-true) (not= first-param 0))
111126
(and (= operation :jump-if-false) (= first-param 0))
112127
) (assoc state :position second-param)
113128
(assoc state :position next-position)))
114129

115130
(:less-than :eq)
116-
(let [first-param (get-param 1 opcode program position)
117-
second-param (get-param 2 opcode program position)
118-
third-param (nth program (+ 3 position))
131+
(let [first-param (get-param 1 opcode state)
132+
second-param (get-param 2 opcode state)
133+
third-param (get-address 3 opcode state)
119134
result ({
120135
:less-than (if (< first-param second-param) 1 0)
121136
:eq (if (= first-param second-param) 1 0)} operation)]
122-
(assoc state
123-
:program (assoc program third-param result)
137+
(assoc (save-to-address third-param result state)
124138
:position next-position
125139
))
140+
141+
:adjust-rel-base (let [first-param (get-param 1 opcode state)]
142+
(assoc state
143+
:rel-base (+ (:rel-base state) first-param)
144+
:position next-position))
126145
)))
127146

128147

@@ -135,4 +154,11 @@
135154

136155

137156
(defn initialize-and-run [& params]
138-
(run (apply initialize-program params)))
157+
(run (apply initialize-program params)))
158+
159+
160+
(defn load-program-from-resource [resource-name]
161+
(apply vector (map #(Integer/parseInt (clojure.string/trim-newline %))
162+
(clojure.string/split
163+
(slurp (io/resource resource-name)) #","))))
164+

test/clj_adventofcode_2019/intcode_test.clj

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(ns clj-adventofcode-2019.intcode-test
22
(:require [clojure.test :refer :all]
3-
[clj-adventofcode-2019.intcode :refer :all]))
3+
[clj-adventofcode-2019.intcode :refer :all]
4+
[clojure.math.numeric-tower :as math]))
45

56

67
(deftest day-02
@@ -95,4 +96,20 @@
9596
(testing "output 1001 if the input value is greater than 8"
9697
(is (= (:output (initialize-and-run program [9]))
9798
[1001]))
98-
)))
99+
)))
100+
101+
(deftest day-09-relative-mode-plus-extra-mem
102+
(testing "takes no input and produces a copy of itself as output"
103+
(let [program [109 1 204 -1 1001 100 1 100 1008 100 16 101 1006 101 0 99]
104+
result (initialize-and-run program)]
105+
(is (= (:output result) program))))
106+
107+
(testing "should output a 16-digit number"
108+
(let [program [1102, 34915192, 34915192, 7, 4, 7, 99, 0]]
109+
(is (> (first (:output (initialize-and-run program))) (math/expt 10 15)))
110+
)
111+
)
112+
113+
(testing "should output the large number in the middle"
114+
(is (= [1125899906842624] (:output (initialize-and-run [104, 1125899906842624, 99])))))
115+
)

0 commit comments

Comments
 (0)