Browse Source

Completed day 11

Tyler Hallada 4 years ago
parent
commit
79645abe5a
5 changed files with 798 additions and 0 deletions
  1. 137 0
      day11/Cargo.lock
  2. 10 0
      day11/Cargo.toml
  3. 1 0
      day11/input/input.txt
  4. 461 0
      day11/src/intcode.rs
  5. 189 0
      day11/src/main.rs

+ 137 - 0
day11/Cargo.lock

@@ -0,0 +1,137 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+[[package]]
4
+name = "day11"
5
+version = "0.1.0"
6
+dependencies = [
7
+ "num_enum 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
8
+]
9
+
10
+[[package]]
11
+name = "derivative"
12
+version = "1.0.3"
13
+source = "registry+https://github.com/rust-lang/crates.io-index"
14
+dependencies = [
15
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
16
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
17
+ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
18
+]
19
+
20
+[[package]]
21
+name = "num_enum"
22
+version = "0.4.2"
23
+source = "registry+https://github.com/rust-lang/crates.io-index"
24
+dependencies = [
25
+ "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
26
+ "num_enum_derive 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
27
+]
28
+
29
+[[package]]
30
+name = "num_enum_derive"
31
+version = "0.4.2"
32
+source = "registry+https://github.com/rust-lang/crates.io-index"
33
+dependencies = [
34
+ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
35
+ "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
36
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
37
+ "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
38
+]
39
+
40
+[[package]]
41
+name = "proc-macro-crate"
42
+version = "0.1.4"
43
+source = "registry+https://github.com/rust-lang/crates.io-index"
44
+dependencies = [
45
+ "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
46
+]
47
+
48
+[[package]]
49
+name = "proc-macro2"
50
+version = "0.4.30"
51
+source = "registry+https://github.com/rust-lang/crates.io-index"
52
+dependencies = [
53
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
54
+]
55
+
56
+[[package]]
57
+name = "proc-macro2"
58
+version = "1.0.7"
59
+source = "registry+https://github.com/rust-lang/crates.io-index"
60
+dependencies = [
61
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
62
+]
63
+
64
+[[package]]
65
+name = "quote"
66
+version = "0.6.13"
67
+source = "registry+https://github.com/rust-lang/crates.io-index"
68
+dependencies = [
69
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
70
+]
71
+
72
+[[package]]
73
+name = "quote"
74
+version = "1.0.2"
75
+source = "registry+https://github.com/rust-lang/crates.io-index"
76
+dependencies = [
77
+ "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
78
+]
79
+
80
+[[package]]
81
+name = "serde"
82
+version = "1.0.104"
83
+source = "registry+https://github.com/rust-lang/crates.io-index"
84
+
85
+[[package]]
86
+name = "syn"
87
+version = "0.15.44"
88
+source = "registry+https://github.com/rust-lang/crates.io-index"
89
+dependencies = [
90
+ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
91
+ "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
92
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
93
+]
94
+
95
+[[package]]
96
+name = "syn"
97
+version = "1.0.13"
98
+source = "registry+https://github.com/rust-lang/crates.io-index"
99
+dependencies = [
100
+ "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
101
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
102
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
103
+]
104
+
105
+[[package]]
106
+name = "toml"
107
+version = "0.5.5"
108
+source = "registry+https://github.com/rust-lang/crates.io-index"
109
+dependencies = [
110
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
111
+]
112
+
113
+[[package]]
114
+name = "unicode-xid"
115
+version = "0.1.0"
116
+source = "registry+https://github.com/rust-lang/crates.io-index"
117
+
118
+[[package]]
119
+name = "unicode-xid"
120
+version = "0.2.0"
121
+source = "registry+https://github.com/rust-lang/crates.io-index"
122
+
123
+[metadata]
124
+"checksum derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a"
125
+"checksum num_enum 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "be601e38e20a6f3d01049d85801cb9b7a34a8da7a0da70df507bbde7735058c8"
126
+"checksum num_enum_derive 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b59f30f6a043f2606adbd0addbf1eef6f2e28e8c4968918b63b7ff97ac0db2a7"
127
+"checksum proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e"
128
+"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
129
+"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
130
+"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
131
+"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
132
+"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
133
+"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
134
+"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
135
+"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
136
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
137
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

+ 10 - 0
day11/Cargo.toml

@@ -0,0 +1,10 @@
1
+[package]
2
+name = "day11"
3
+version = "0.1.0"
4
+authors = ["Tyler Hallada <tyler@hallada.net>"]
5
+edition = "2018"
6
+
7
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
+
9
+[dependencies]
10
+num_enum = "0.4.2"

File diff suppressed because it is too large
+ 1 - 0
day11/input/input.txt


+ 461 - 0
day11/src/intcode.rs

@@ -0,0 +1,461 @@
1
+use std::collections::HashMap;
2
+use std::convert::TryFrom;
3
+use std::error::Error;
4
+use std::fs::File;
5
+use std::io::prelude::*;
6
+use std::result;
7
+use std::str::FromStr;
8
+
9
+use num_enum::TryFromPrimitive;
10
+
11
+type Result<T> = result::Result<T, Box<dyn Error>>;
12
+
13
+#[derive(Debug, Clone, PartialEq)]
14
+pub struct Intcode {
15
+    pub integers: HashMap<usize, i64>,
16
+    pub pointer: usize,
17
+    pub halted: bool,
18
+    pub relative_base: i64,
19
+}
20
+
21
+#[derive(Debug, PartialEq)]
22
+pub struct Instruction {
23
+    opcode: Opcode,
24
+    parameter_modes: Vec<ParameterMode>,
25
+}
26
+
27
+impl TryFrom<i64> for Instruction {
28
+    type Error = Box<dyn Error>;
29
+
30
+    fn try_from(integer: i64) -> Result<Self> {
31
+        let opcode: Opcode = Opcode::try_from((integer % 100) as u8)?;
32
+        let modes_integer = integer / 100;
33
+        let mut parameter_modes = vec![];
34
+        for parameter_index in 0..opcode.parameter_count() {
35
+            parameter_modes.push(ParameterMode::try_from(
36
+                (modes_integer % (10_i64.pow(parameter_index + 1)) / 10_i64.pow(parameter_index))
37
+                    as u8,
38
+            )?)
39
+        }
40
+        Ok(Instruction {
41
+            opcode,
42
+            parameter_modes,
43
+        })
44
+    }
45
+}
46
+
47
+#[derive(Debug, PartialEq, TryFromPrimitive)]
48
+#[repr(u8)]
49
+pub enum Opcode {
50
+    Add = 1,
51
+    Mult = 2,
52
+    Input = 3,
53
+    Output = 4,
54
+    JumpIfTrue = 5,
55
+    JumpIfFalse = 6,
56
+    LessThan = 7,
57
+    Equals = 8,
58
+    RelativeBaseOffset = 9,
59
+    Halt = 99,
60
+}
61
+
62
+impl Opcode {
63
+    pub fn parameter_count(&self) -> u32 {
64
+        match self {
65
+            Opcode::Add => 3,
66
+            Opcode::Mult => 3,
67
+            Opcode::Input => 1,
68
+            Opcode::Output => 1,
69
+            Opcode::JumpIfTrue => 2,
70
+            Opcode::JumpIfFalse => 2,
71
+            Opcode::LessThan => 3,
72
+            Opcode::Equals => 3,
73
+            Opcode::RelativeBaseOffset => 1,
74
+            Opcode::Halt => 0,
75
+        }
76
+    }
77
+
78
+    pub fn target_parameter_index(&self) -> Option<usize> {
79
+        match self {
80
+            Opcode::Add => Some(2),
81
+            Opcode::Mult => Some(2),
82
+            Opcode::Input => Some(0),
83
+            Opcode::Output => None,
84
+            Opcode::JumpIfTrue => None,
85
+            Opcode::JumpIfFalse => None,
86
+            Opcode::LessThan => Some(2),
87
+            Opcode::Equals => Some(2),
88
+            Opcode::RelativeBaseOffset => None,
89
+            Opcode::Halt => None,
90
+        }
91
+    }
92
+}
93
+
94
+#[derive(Debug, PartialEq, TryFromPrimitive)]
95
+#[repr(u8)]
96
+pub enum ParameterMode {
97
+    Position = 0,
98
+    Immediate = 1,
99
+    Relative = 2,
100
+}
101
+
102
+impl FromStr for Intcode {
103
+    type Err = Box<dyn Error>;
104
+
105
+    fn from_str(s: &str) -> Result<Intcode> {
106
+        let intcode_string = s.trim().to_string();
107
+        let mut integers = HashMap::new();
108
+        for (index, code) in intcode_string.split(',').enumerate() {
109
+            integers.insert(index, code.parse().unwrap());
110
+        }
111
+
112
+        Ok(Intcode::new(integers))
113
+    }
114
+}
115
+
116
+impl Intcode {
117
+    fn new(integers: HashMap<usize, i64>) -> Intcode {
118
+        Intcode {
119
+            integers,
120
+            pointer: 0,
121
+            halted: false,
122
+            relative_base: 0,
123
+        }
124
+    }
125
+
126
+    fn load_parameters(&mut self, pointer: usize, instruction: &Instruction) -> Vec<i64> {
127
+        (0..instruction.opcode.parameter_count() as usize)
128
+            .map(|parameter_index| {
129
+                let mut integer = *self
130
+                    .integers
131
+                    .entry(pointer + parameter_index + 1)
132
+                    .or_insert(0);
133
+                match instruction.parameter_modes[parameter_index] {
134
+                    ParameterMode::Position => match instruction.opcode.target_parameter_index() {
135
+                        Some(target_parameter_index)
136
+                            if target_parameter_index == parameter_index => {}
137
+                        _ => {
138
+                            integer = *self.integers.entry(integer as usize).or_insert(0);
139
+                        }
140
+                    },
141
+                    ParameterMode::Relative => match instruction.opcode.target_parameter_index() {
142
+                        Some(target_parameter_index)
143
+                            if target_parameter_index == parameter_index =>
144
+                        {
145
+                            integer += self.relative_base;
146
+                        }
147
+                        _ => {
148
+                            integer = *self
149
+                                .integers
150
+                                .entry((self.relative_base + integer) as usize)
151
+                                .or_insert(0);
152
+                        }
153
+                    },
154
+                    _ => {}
155
+                }
156
+                integer
157
+            })
158
+            .collect()
159
+    }
160
+
161
+    pub fn execute(&mut self, inputs: &[i64]) -> Result<Vec<i64>> {
162
+        let mut input_index = 0;
163
+        let mut output = vec![];
164
+
165
+        loop {
166
+            let instruction =
167
+                Instruction::try_from(*self.integers.entry(self.pointer).or_insert(0))?;
168
+            let parameters = self.load_parameters(self.pointer, &instruction);
169
+            let mut jump_pointer: Option<usize> = None;
170
+
171
+            match instruction.opcode {
172
+                Opcode::Add => {
173
+                    self.integers
174
+                        .insert(parameters[2] as usize, parameters[0] + parameters[1]);
175
+                }
176
+                Opcode::Mult => {
177
+                    self.integers
178
+                        .insert(parameters[2] as usize, parameters[0] * parameters[1]);
179
+                }
180
+                Opcode::Input => {
181
+                    if input_index >= inputs.len() {
182
+                        break; // pause execution to wait for more input
183
+                    }
184
+                    self.integers
185
+                        .insert(parameters[0] as usize, inputs[input_index]);
186
+                    input_index += 1;
187
+                }
188
+                Opcode::Output => {
189
+                    output.push(parameters[0]);
190
+                }
191
+                Opcode::JumpIfTrue => {
192
+                    if parameters[0] != 0 {
193
+                        jump_pointer = Some(parameters[1] as usize);
194
+                    }
195
+                }
196
+                Opcode::JumpIfFalse => {
197
+                    if parameters[0] == 0 {
198
+                        jump_pointer = Some(parameters[1] as usize);
199
+                    }
200
+                }
201
+                Opcode::LessThan => {
202
+                    if parameters[0] < parameters[1] {
203
+                        self.integers.insert(parameters[2] as usize, 1);
204
+                    } else {
205
+                        self.integers.insert(parameters[2] as usize, 0);
206
+                    }
207
+                }
208
+                Opcode::Equals => {
209
+                    if parameters[0] == parameters[1] {
210
+                        self.integers.insert(parameters[2] as usize, 1);
211
+                    } else {
212
+                        self.integers.insert(parameters[2] as usize, 0);
213
+                    }
214
+                }
215
+                Opcode::RelativeBaseOffset => {
216
+                    self.relative_base += parameters[0];
217
+                }
218
+                Opcode::Halt => {
219
+                    self.halted = true;
220
+                    break;
221
+                }
222
+            }
223
+
224
+            match jump_pointer {
225
+                Some(jump_pointer) => self.pointer = jump_pointer,
226
+                None => self.pointer += 1 + instruction.opcode.parameter_count() as usize,
227
+            }
228
+        }
229
+
230
+        Ok(output)
231
+    }
232
+}
233
+
234
+pub fn read_intcode(filename: &str) -> Result<Intcode> {
235
+    let mut file = File::open(filename)?;
236
+    let mut intcode_string = String::new();
237
+    file.read_to_string(&mut intcode_string)?;
238
+
239
+    Ok(intcode_string.parse()?)
240
+}
241
+
242
+#[cfg(test)]
243
+mod tests {
244
+    use super::*;
245
+
246
+    const TEST_INPUT: &str = "input/test1.txt";
247
+
248
+    #[test]
249
+    fn reads_intcode() {
250
+        assert_eq!(
251
+            read_intcode(TEST_INPUT).unwrap(),
252
+            Intcode::new(
253
+                vec![3, 15, 3, 16, 1002, 16, 10, 16, 1, 16, 15, 15, 4, 15, 99, 0, 0]
254
+                    .into_iter()
255
+                    .enumerate()
256
+                    .collect()
257
+            ),
258
+        );
259
+    }
260
+
261
+    #[test]
262
+    fn converts_integer_to_instruction() {
263
+        assert_eq!(
264
+            Instruction::try_from(1002).unwrap(),
265
+            Instruction {
266
+                opcode: Opcode::Mult,
267
+                parameter_modes: vec![
268
+                    ParameterMode::Position,
269
+                    ParameterMode::Immediate,
270
+                    ParameterMode::Position
271
+                ],
272
+            }
273
+        );
274
+
275
+        assert_eq!(
276
+            Instruction::try_from(101).unwrap(),
277
+            Instruction {
278
+                opcode: Opcode::Add,
279
+                parameter_modes: vec![
280
+                    ParameterMode::Immediate,
281
+                    ParameterMode::Position,
282
+                    ParameterMode::Position
283
+                ],
284
+            }
285
+        );
286
+    }
287
+
288
+    #[test]
289
+    fn executes_intcodes() {
290
+        let mut intcode = Intcode::new(vec![1, 0, 0, 0, 99].into_iter().enumerate().collect());
291
+        intcode.execute(&[0]).unwrap();
292
+        assert_eq!(
293
+            intcode.integers,
294
+            vec![2, 0, 0, 0, 99].into_iter().enumerate().collect()
295
+        );
296
+
297
+        let mut intcode = Intcode::new(vec![2, 3, 0, 3, 99].into_iter().enumerate().collect());
298
+        intcode.execute(&[0]).unwrap();
299
+        assert_eq!(
300
+            intcode.integers,
301
+            vec![2, 3, 0, 6, 99].into_iter().enumerate().collect()
302
+        );
303
+
304
+        let mut intcode = Intcode::new(vec![2, 4, 4, 5, 99, 0].into_iter().enumerate().collect());
305
+        intcode.execute(&[0]).unwrap();
306
+        assert_eq!(
307
+            intcode.integers,
308
+            vec![2, 4, 4, 5, 99, 9801].into_iter().enumerate().collect()
309
+        );
310
+
311
+        let mut intcode = Intcode::new(
312
+            vec![1, 1, 1, 4, 99, 5, 6, 0, 99]
313
+                .into_iter()
314
+                .enumerate()
315
+                .collect(),
316
+        );
317
+        intcode.execute(&[0]).unwrap();
318
+        assert_eq!(
319
+            intcode.integers,
320
+            vec![30, 1, 1, 4, 2, 5, 6, 0, 99]
321
+                .into_iter()
322
+                .enumerate()
323
+                .collect()
324
+        );
325
+
326
+        let mut intcode = Intcode::new(
327
+            vec![1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50]
328
+                .into_iter()
329
+                .enumerate()
330
+                .collect(),
331
+        );
332
+        intcode.execute(&[0]).unwrap();
333
+        assert_eq!(
334
+            intcode.integers,
335
+            vec![3500, 9, 10, 70, 2, 3, 11, 0, 99, 30, 40, 50]
336
+                .into_iter()
337
+                .enumerate()
338
+                .collect()
339
+        );
340
+    }
341
+
342
+    #[test]
343
+    fn less_and_equal_outputs() {
344
+        let intcode = Intcode::new(
345
+            vec![3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8]
346
+                .into_iter()
347
+                .enumerate()
348
+                .collect(),
349
+        );
350
+        assert_eq!(intcode.clone().execute(&[8]).unwrap(), vec![1]);
351
+        assert_eq!(intcode.clone().execute(&[0]).unwrap(), vec![0]);
352
+
353
+        let intcode = Intcode::new(
354
+            vec![3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8]
355
+                .into_iter()
356
+                .enumerate()
357
+                .collect(),
358
+        );
359
+        assert_eq!(intcode.clone().execute(&[0]).unwrap(), vec![1]);
360
+        assert_eq!(intcode.clone().execute(&[9]).unwrap(), vec![0]);
361
+
362
+        let intcode = Intcode::new(
363
+            vec![3, 3, 1108, -1, 8, 3, 4, 3, 99]
364
+                .into_iter()
365
+                .enumerate()
366
+                .collect(),
367
+        );
368
+        assert_eq!(intcode.clone().execute(&[8]).unwrap(), vec![1]);
369
+        assert_eq!(intcode.clone().execute(&[0]).unwrap(), vec![0]);
370
+
371
+        let intcode = Intcode::new(
372
+            vec![3, 3, 1107, -1, 8, 3, 4, 3, 99]
373
+                .into_iter()
374
+                .enumerate()
375
+                .collect(),
376
+        );
377
+        assert_eq!(intcode.clone().execute(&[0]).unwrap(), vec![1]);
378
+        assert_eq!(intcode.clone().execute(&[9]).unwrap(), vec![0]);
379
+    }
380
+
381
+    #[test]
382
+    fn jump_outputs() {
383
+        let intcode = Intcode::new(
384
+            vec![3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9]
385
+                .into_iter()
386
+                .enumerate()
387
+                .collect(),
388
+        );
389
+        assert_eq!(intcode.clone().execute(&[0]).unwrap(), vec![0]);
390
+        assert_eq!(intcode.clone().execute(&[1]).unwrap(), vec![1]);
391
+
392
+        let intcode = Intcode::new(
393
+            vec![3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1]
394
+                .into_iter()
395
+                .enumerate()
396
+                .collect(),
397
+        );
398
+        assert_eq!(intcode.clone().execute(&[0]).unwrap(), vec![0]);
399
+        assert_eq!(intcode.clone().execute(&[1]).unwrap(), vec![1]);
400
+    }
401
+
402
+    #[test]
403
+    fn larger_part2_intcode() {
404
+        let intcode = Intcode::new(
405
+            vec![
406
+                3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36,
407
+                98, 0, 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000,
408
+                1, 20, 4, 20, 1105, 1, 46, 98, 99,
409
+            ]
410
+            .into_iter()
411
+            .enumerate()
412
+            .collect(),
413
+        );
414
+        assert_eq!(intcode.clone().execute(&[0]).unwrap(), vec![999]);
415
+        assert_eq!(intcode.clone().execute(&[8]).unwrap(), vec![1000]);
416
+        assert_eq!(intcode.clone().execute(&[9]).unwrap(), vec![1001]);
417
+    }
418
+
419
+    #[test]
420
+    fn multiple_input_intcode() {
421
+        let intcode = Intcode::new(
422
+            vec![
423
+                3, 15, 3, 16, 1002, 16, 10, 16, 1, 16, 15, 15, 4, 15, 99, 0, 0,
424
+            ]
425
+            .into_iter()
426
+            .enumerate()
427
+            .collect(),
428
+        );
429
+        assert_eq!(intcode.clone().execute(&[1, 1]).unwrap(), vec![11]);
430
+    }
431
+
432
+    #[test]
433
+    fn relative_base_offset_quine() {
434
+        let code = vec![
435
+            109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99,
436
+        ];
437
+        let intcode = Intcode::new(code.clone().into_iter().enumerate().collect());
438
+        assert_eq!(intcode.clone().execute(&[]).unwrap(), code);
439
+    }
440
+
441
+    #[test]
442
+    fn sixteen_digit_output() {
443
+        let code = vec![1102, 34915192, 34915192, 7, 4, 7, 99, 0];
444
+        let intcode = Intcode::new(code.into_iter().enumerate().collect());
445
+        assert_eq!(intcode.clone().execute(&[]).unwrap(), [1219070632396864]);
446
+    }
447
+
448
+    #[test]
449
+    fn large_output() {
450
+        let code = vec![104, 1125899906842624, 99];
451
+        let intcode = Intcode::new(code.into_iter().enumerate().collect());
452
+        assert_eq!(intcode.clone().execute(&[]).unwrap(), [1125899906842624]);
453
+    }
454
+
455
+    #[test]
456
+    fn relative_target_parameters() {
457
+        let code = vec![109, 1, 203, 2, 204, 2, 99];
458
+        let intcode = Intcode::new(code.into_iter().enumerate().collect());
459
+        assert_eq!(intcode.clone().execute(&[123]).unwrap(), [123]);
460
+    }
461
+}

+ 189 - 0
day11/src/main.rs

@@ -0,0 +1,189 @@
1
+use std::collections::HashMap;
2
+use std::convert::TryFrom;
3
+use std::error::Error;
4
+use std::fmt;
5
+use std::result;
6
+
7
+use num_enum::TryFromPrimitive;
8
+
9
+mod intcode;
10
+
11
+use intcode::{read_intcode, Intcode};
12
+
13
+const INPUT: &str = "input/input.txt";
14
+
15
+type Result<T> = result::Result<T, Box<dyn Error>>;
16
+
17
+#[derive(TryFromPrimitive, Clone, Copy)]
18
+#[repr(u8)]
19
+enum Color {
20
+    Black = 0,
21
+    White = 1,
22
+}
23
+
24
+#[derive(TryFromPrimitive, Clone, Copy)]
25
+#[repr(u8)]
26
+enum Turn {
27
+    Left = 0,
28
+    Right = 1,
29
+}
30
+
31
+#[derive(TryFromPrimitive, Clone, Copy)]
32
+#[repr(u8)]
33
+enum Direction {
34
+    Left = 0,
35
+    Right = 1,
36
+    Up = 2,
37
+    Down = 3,
38
+}
39
+
40
+impl Direction {
41
+    fn turn(&self, turn: Turn) -> Direction {
42
+        match turn {
43
+            Turn::Left => match self {
44
+                Direction::Left => Direction::Down,
45
+                Direction::Right => Direction::Up,
46
+                Direction::Up => Direction::Left,
47
+                Direction::Down => Direction::Right,
48
+            },
49
+            Turn::Right => match self {
50
+                Direction::Left => Direction::Up,
51
+                Direction::Right => Direction::Down,
52
+                Direction::Up => Direction::Right,
53
+                Direction::Down => Direction::Left,
54
+            },
55
+        }
56
+    }
57
+}
58
+
59
+#[derive(PartialEq, Eq, Hash, Clone, Copy)]
60
+struct Coordinate {
61
+    x: i64,
62
+    y: i64,
63
+}
64
+
65
+struct Robot {
66
+    intcode: Intcode,
67
+    position: Coordinate,
68
+    direction: Direction,
69
+}
70
+
71
+impl Robot {
72
+    fn new(intcode: Intcode) -> Robot {
73
+        Robot {
74
+            intcode: intcode.clone(),
75
+            position: Coordinate { x: 0, y: 0 },
76
+            direction: Direction::Up,
77
+        }
78
+    }
79
+
80
+    fn turn_and_move(&mut self, turn: Turn) {
81
+        self.direction = self.direction.turn(turn);
82
+        match self.direction {
83
+            Direction::Left => self.position.x -= 1,
84
+            Direction::Right => self.position.x += 1,
85
+            Direction::Up => self.position.y -= 1,
86
+            Direction::Down => self.position.y += 1,
87
+        }
88
+    }
89
+}
90
+
91
+struct Hull {
92
+    panels: HashMap<Coordinate, Color>,
93
+}
94
+
95
+impl Hull {
96
+    fn new() -> Hull {
97
+        Hull {
98
+            panels: HashMap::new(),
99
+        }
100
+    }
101
+
102
+    fn paint_registration(&mut self, intcode: Intcode, start_color: Color) -> Result<()> {
103
+        let mut robot = Robot::new(intcode);
104
+        let mut current_panel = start_color;
105
+        while !robot.intcode.halted {
106
+            let output = robot
107
+                .intcode
108
+                .execute(&[current_panel as i64])
109
+                .expect("Failed to execute intcode");
110
+            let color = Color::try_from(output[0] as u8)?;
111
+            let turn = Turn::try_from(output[1] as u8)?;
112
+
113
+            self.panels.insert(robot.position, color);
114
+            robot.turn_and_move(turn);
115
+            current_panel = *self.panels.get(&robot.position).unwrap_or(&Color::Black);
116
+        }
117
+        Ok(())
118
+    }
119
+}
120
+
121
+impl fmt::Display for Hull {
122
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123
+        let start_coord = Coordinate { x: 0, y: 0 };
124
+        let up_left_corner = Coordinate {
125
+            x: self
126
+                .panels
127
+                .keys()
128
+                .min_by_key(|coord| coord.x)
129
+                .unwrap_or(&start_coord)
130
+                .x,
131
+            y: self
132
+                .panels
133
+                .keys()
134
+                .min_by_key(|coord| coord.y)
135
+                .unwrap_or(&start_coord)
136
+                .y,
137
+        };
138
+        let down_right_corner = Coordinate {
139
+            x: self
140
+                .panels
141
+                .keys()
142
+                .max_by_key(|coord| coord.x)
143
+                .unwrap_or(&start_coord)
144
+                .x,
145
+            y: self
146
+                .panels
147
+                .keys()
148
+                .max_by_key(|coord| coord.y)
149
+                .unwrap_or(&start_coord)
150
+                .y,
151
+        };
152
+        for y in up_left_corner.y..=down_right_corner.y {
153
+            let mut row_string = String::new();
154
+            for x in up_left_corner.x..=down_right_corner.x {
155
+                row_string += match self
156
+                    .panels
157
+                    .get(&Coordinate { x, y })
158
+                    .unwrap_or(&Color::Black)
159
+                {
160
+                    Color::Black => ".",
161
+                    Color::White => "#",
162
+                };
163
+            }
164
+            write!(f, "{}\n", row_string)?;
165
+        }
166
+        Ok(())
167
+    }
168
+}
169
+
170
+fn solve_part1() -> Result<usize> {
171
+    let intcode = read_intcode(INPUT)?;
172
+    let mut hull = Hull::new();
173
+    hull.paint_registration(intcode, Color::Black)?;
174
+    Ok(hull.panels.len())
175
+}
176
+
177
+fn solve_part2() -> Result<String> {
178
+    let intcode = read_intcode(INPUT)?;
179
+    let mut hull = Hull::new();
180
+    hull.paint_registration(intcode, Color::White)?;
181
+    Ok(format!("\n{}", hull))
182
+}
183
+
184
+fn main() -> Result<()> {
185
+    println!("Part 1: {}", solve_part1()?);
186
+    println!("Part 2: {}", solve_part2()?);
187
+
188
+    Ok(())
189
+}