* Day 11
authorGrégory Burri <gregory.burri@matisa.ch>
Wed, 11 Dec 2019 15:25:37 +0000 (16:25 +0100)
committerGrégory Burri <gregory.burri@matisa.ch>
Wed, 11 Dec 2019 15:25:37 +0000 (16:25 +0100)
* Merge intcode from day 05 and day09 to 'intcode' module

data/day11.input [new file with mode: 0644]
src/common.rs
src/day02.rs
src/day05.rs [deleted file]
src/day06.rs
src/day07.rs
src/day08.rs
src/day09.rs [deleted file]
src/day11.rs [new file with mode: 0644]
src/intcode.rs [new file with mode: 0644]
src/main.rs

diff --git a/data/day11.input b/data/day11.input
new file mode 100644 (file)
index 0000000..a81f133
--- /dev/null
@@ -0,0 +1 @@
+3,8,1005,8,305,1106,0,11,0,0,0,104,1,104,0,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,0,10,4,10,1002,8,1,29,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,1002,8,1,50,1,104,20,10,1,1102,6,10,1006,0,13,3,8,102,-1,8,10,101,1,10,10,4,10,108,1,8,10,4,10,102,1,8,83,1,1102,0,10,1006,0,96,2,1004,19,10,3,8,1002,8,-1,10,101,1,10,10,4,10,108,0,8,10,4,10,101,0,8,116,3,8,1002,8,-1,10,1001,10,1,10,4,10,108,1,8,10,4,10,102,1,8,138,1006,0,60,1,1008,12,10,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,0,10,4,10,102,1,8,168,1006,0,14,1006,0,28,3,8,1002,8,-1,10,1001,10,1,10,4,10,108,0,8,10,4,10,101,0,8,195,2,1005,9,10,1006,0,29,3,8,1002,8,-1,10,101,1,10,10,4,10,108,1,8,10,4,10,1002,8,1,224,2,1009,8,10,1,3,5,10,3,8,1002,8,-1,10,101,1,10,10,4,10,108,1,8,10,4,10,102,1,8,254,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,0,10,4,10,1002,8,1,277,1,1003,18,10,1,1104,1,10,101,1,9,9,1007,9,957,10,1005,10,15,99,109,627,104,0,104,1,21101,0,666681062292,1,21102,322,1,0,1105,1,426,21101,847073883028,0,1,21102,333,1,0,1105,1,426,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,21101,0,179356855319,1,21102,1,380,0,1105,1,426,21102,1,179356998696,1,21102,1,391,0,1105,1,426,3,10,104,0,104,0,3,10,104,0,104,0,21101,0,988669698816,1,21101,0,414,0,1106,0,426,21102,1,868494500628,1,21102,425,1,0,1106,0,426,99,109,2,21202,-1,1,1,21102,1,40,2,21102,457,1,3,21102,1,447,0,1105,1,490,109,-2,2105,1,0,0,1,0,0,1,109,2,3,10,204,-1,1001,452,453,468,4,0,1001,452,1,452,108,4,452,10,1006,10,484,1102,0,1,452,109,-2,2105,1,0,0,109,4,1201,-1,0,489,1207,-3,0,10,1006,10,507,21102,0,1,-3,22101,0,-3,1,21202,-2,1,2,21101,1,0,3,21102,1,526,0,1106,0,531,109,-4,2105,1,0,109,5,1207,-3,1,10,1006,10,554,2207,-4,-2,10,1006,10,554,22101,0,-4,-4,1106,0,622,21201,-4,0,1,21201,-3,-1,2,21202,-2,2,3,21102,573,1,0,1106,0,531,21202,1,1,-4,21101,1,0,-1,2207,-4,-2,10,1006,10,592,21102,1,0,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,614,22101,0,-1,1,21102,614,1,0,105,1,489,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2105,1,0
\ No newline at end of file
index 30155d0..b3db167 100644 (file)
@@ -10,4 +10,22 @@ where
 \r
 {\r
     fs::read_to_string(file).unwrap().split(sep).map(|line| line.parse::<T>().unwrap()).collect()\r
+}\r
+\r
+pub fn layer_to_printable_string(layer: &[u8], width: usize) -> String {\r
+    let mut result = String::new();\r
+    let mut i = 0;\r
+\r
+    loop {\r
+        for _ in 0 .. width {\r
+            if layer[i] == 0 {\r
+                result += " ";\r
+            } else {\r
+                result += "█";\r
+            }\r
+            i += 1;\r
+            if i >= layer.len() { return result }\r
+        }\r
+        result += "\n";\r
+    }\r
 }
\ No newline at end of file
index 81dfaaf..fd26331 100644 (file)
@@ -11,7 +11,7 @@ fn execute_op_code(code: &mut [i32]) -> i32 {
             1 => code[code[cursor + 3] as usize] = code[code[cursor + 1] as usize] + code[code[cursor + 2] as usize],\r
             2 => code[code[cursor + 3] as usize] = code[code[cursor + 1] as usize] * code[code[cursor + 2] as usize],\r
             99 => return code[0],\r
-            _ => panic!("Unkown code: {}", code[cursor])\r
+            _ => panic!("Unknown code: {}", code[cursor])\r
         }\r
         cursor += 4;\r
     }\r
diff --git a/src/day05.rs b/src/day05.rs
deleted file mode 100644 (file)
index 61f6203..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// 'true' -> immediate mode, 'false' -> position mode.\r
-fn read_op_and_modes(mut code: i32) -> (i32, [bool; 3]) {\r
-    let mut modes: [bool; 3] = [ false, false, false ];\r
-\r
-    if code >= 10_000 {\r
-        modes[2] = true;\r
-        code -= 10_000;\r
-    }\r
-\r
-    if code >= 1_000 {\r
-        modes[1] = true;\r
-        code -= 1_000;\r
-    }\r
-\r
-    if code >= 100 {\r
-        modes[0] = true;\r
-        code -= 100;\r
-    }\r
-\r
-    (code, modes)\r
-}\r
-\r
-pub fn execute_op_code(code: &mut [i32], input: &[i32]) -> Vec<i32> {\r
-    let mut cursor = 0;\r
-    let mut input_cursor = 0;\r
-    let mut output = Vec::<i32>::new();\r
-\r
-    fn read(position: usize, code: &[i32], mode: bool) -> i32 {\r
-        if mode { code[position] } else { code[code[position] as usize] }\r
-    };\r
-\r
-    fn jump_if(cond: bool, cursor: usize, code: &[i32], modes: [bool; 3]) -> usize {\r
-        let value = read(cursor + 1, &code, modes[0]);\r
-        if cond == (value != 0) {\r
-            read(cursor + 2, &code, modes[1]) as usize\r
-        } else {\r
-            cursor + 3\r
-        }\r
-    };\r
-\r
-    loop {\r
-        let (op, modes) = read_op_and_modes(code[cursor]);\r
-\r
-        match op {\r
-            // Sum.\r
-            1 => {\r
-                code[code[cursor + 3] as usize] = read(cursor + 1, &code, modes[0]) + read(cursor + 2, &code, modes[1]);\r
-                cursor += 4;\r
-            },\r
-\r
-            // Multiply.\r
-            2 => {\r
-                code[code[cursor + 3] as usize] = read(cursor + 1, &code, modes[0]) * read(cursor + 2, &code, modes[1]);\r
-                cursor += 4;\r
-            },\r
-\r
-            // Input.\r
-            3 => {\r
-                code[code[cursor + 1] as usize] = input[input_cursor];\r
-                input_cursor += 1;\r
-                cursor += 2;\r
-            }\r
-\r
-            // Output.\r
-            4 => {\r
-                output.push(read(cursor + 1, &code, modes[0]));\r
-                cursor += 2;\r
-            }\r
-\r
-            // Jump-if-true.\r
-            5 => cursor = jump_if(true, cursor, &code, modes),\r
-\r
-            // Jump-if-false.\r
-            6 => cursor = jump_if(false, cursor, &code, modes),\r
-\r
-            // Less than.\r
-            7 => {\r
-                code[code[cursor + 3] as usize] =\r
-                    if read(cursor + 1, &code, modes[0]) < read(cursor + 2, &code, modes[1]) { 1 } else { 0 };\r
-                cursor += 4;\r
-            },\r
-\r
-            // Equals.\r
-            8 => {\r
-                code[code[cursor + 3] as usize] =\r
-                    if read(cursor + 1, &code, modes[0]) == read(cursor + 2, &code, modes[1]) { 1 } else { 0 };\r
-                cursor += 4;\r
-            },\r
-\r
-            99 => break,\r
-            _ => panic!("Unkown code: {}", code[cursor])\r
-        }\r
-    }\r
-    output\r
-}\r
-\r
-#[cfg(test)]\r
-mod tests {\r
-    use super::*;\r
-\r
-    #[test]\r
-    fn part1() {\r
-        let mut c = [1002, 4, 3, 4, 33];\r
-        let _ = execute_op_code(&mut c, &Vec::new());\r
-        assert_eq!(c[4], 99);\r
-    }\r
-\r
-    #[test]\r
-    fn part2() {\r
-        let c = [3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99];\r
-\r
-        let mut c1 = c;\r
-        let r1 = execute_op_code(&mut c1, &[7]);\r
-        assert_eq!(r1[0], 999);\r
-\r
-        let mut c2 = c;\r
-        let r2 = execute_op_code(&mut c2, &[8]);\r
-        assert_eq!(r2[0], 1000);\r
-\r
-        let mut c3 = c;\r
-        let r3 = execute_op_code(&mut c3, &[9]);\r
-        assert_eq!(r3[0], 1001);\r
-    }\r
-}
\ No newline at end of file
index fddb899..c0d4ae0 100644 (file)
@@ -41,7 +41,7 @@ pub fn nb_orbital_transfers(orbits: &Orbits, loc1: &str, loc2: &str) -> usize {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test]
index e69de29..fea25ff 100644 (file)
@@ -0,0 +1,11 @@
+\r
+\r
+\r
+#[cfg(test)]\r
+mod tests {\r
+\r
+    #[test]\r
+    fn part1 () {\r
+\r
+    }\r
+}
\ No newline at end of file
index 95b0385..50fb119 100644 (file)
@@ -47,24 +47,6 @@ pub fn merge_layers(layers: &[Vec<u8>]) -> Vec<u8> {
     result
 }
 
-pub fn layer_to_printable_string(layer: &[u8], width: u32) -> String {
-    let mut result = String::new();
-    let mut i = 0;
-
-    loop {
-        for _ in 0 .. width {
-            if layer[i] == 0 {
-                result += " ";
-            } else {
-                result += "█";
-            }
-            i += 1;
-            if i >= layer.len() { return result }
-        }
-        result += "\n";
-    }
-}
-
 pub fn one_digits_times_two_digits(layer: &[u8]) -> u32 {
     count(layer, 1) * count(layer, 2)
 }
diff --git a/src/day09.rs b/src/day09.rs
deleted file mode 100644 (file)
index ea234b2..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-#[derive(Copy, Clone, Debug)]\r
-enum Mode {\r
-    Position,\r
-    Immediate,\r
-    Relative\r
-}\r
-\r
-// 'true' -> immediate mode, 'false' -> position mode.\r
-fn read_op_and_modes(mut code: i64) -> (i64, [Mode; 3]) {\r
-    let mut modes: [Mode; 3] = [ Mode::Position, Mode::Position, Mode::Position ];\r
-\r
-    for i in (2..=4).rev() {\r
-        let power = 10i64.pow(i);\r
-        if code >= 2 * power {\r
-            modes[i as usize - 2] = Mode::Relative;\r
-            code -= 2 * power;\r
-        } else if code >= power {\r
-            modes[i as usize - 2] = Mode::Immediate;\r
-            code -= power;\r
-        }\r
-    }\r
-\r
-    (code, modes)\r
-}\r
-\r
-pub fn execute_op_code(code: &[i64], input: &[i64]) -> Vec<i64> {\r
-    let mut code = Vec::from(code);\r
-    let mut cursor = 0;\r
-    let mut input_cursor = 0;\r
-    let mut output = Vec::<i64>::new();\r
-    let mut relative_base = 0;\r
-\r
-    fn read(position: usize, code: &[i64], mode: Mode, relative_base: i64) -> i64 {\r
-        if position >= code.len() { return 0 }\r
-\r
-        match mode {\r
-            Mode::Position => if code[position] as usize >= code.len() { 0 } else { code[code[position] as usize] },\r
-            Mode::Immediate => code[position],\r
-            Mode::Relative => if (code[position] + relative_base) as usize >= code.len() { 0 } else { code[(code[position] + relative_base) as usize] }\r
-        }\r
-    };\r
-\r
-    fn write(position: usize, value: i64, code: &mut Vec<i64>, mode: Mode, relative_base: i64) {\r
-        let ref_position =\r
-            match mode {\r
-                Mode::Position => code[position] as usize,\r
-                Mode::Immediate => panic!("Can't write un immediate mode"),\r
-                Mode::Relative => (code[position] + relative_base) as usize\r
-            };\r
-\r
-        if ref_position >= code.len() {\r
-            code.resize(ref_position + 1, 0);\r
-        }\r
-\r
-        code[ref_position] = value;\r
-    }\r
-\r
-    fn jump_if(cond: bool, cursor: usize, code: &[i64], modes: [Mode; 3], relative_base: i64) -> usize {\r
-        let value = read(cursor + 1, &code, modes[0], relative_base);\r
-        if cond == (value != 0) {\r
-            read(cursor + 2, &code, modes[1], relative_base) as usize\r
-        } else {\r
-            cursor + 3\r
-        }\r
-    };\r
-\r
-    loop {\r
-        let (op, modes) = read_op_and_modes(code[cursor]);\r
-\r
-        match op {\r
-            // Sum.\r
-            1 => {\r
-                write(cursor + 3, read(cursor + 1, &code, modes[0], relative_base) + read(cursor + 2, &code, modes[1], relative_base), &mut code, modes[2], relative_base);\r
-                cursor += 4;\r
-            },\r
-\r
-            // Multiply.\r
-            2 => {\r
-                write(cursor + 3, read(cursor + 1, &code, modes[0], relative_base) * read(cursor + 2, &code, modes[1], relative_base), &mut code, modes[2], relative_base);\r
-                cursor += 4;\r
-            },\r
-\r
-            // Input.\r
-            3 => {\r
-                write(cursor + 1, input[input_cursor], &mut code, modes[0], relative_base);\r
-                input_cursor += 1;\r
-                cursor += 2;\r
-            }\r
-\r
-            // Output.\r
-            4 => {\r
-                output.push(read(cursor + 1, &code, modes[0], relative_base));\r
-                cursor += 2;\r
-            }\r
-\r
-            // Jump-if-true.\r
-            5 => cursor = jump_if(true, cursor, &code, modes, relative_base),\r
-\r
-            // Jump-if-false.\r
-            6 => cursor = jump_if(false, cursor, &code, modes, relative_base),\r
-\r
-            // Less than.\r
-            7 => {\r
-                write(cursor + 3, if read(cursor + 1, &code, modes[0], relative_base) < read(cursor + 2, &code, modes[1], relative_base) { 1 } else { 0 }, &mut code, modes[2], relative_base);\r
-                cursor += 4;\r
-            },\r
-\r
-            // Equals.\r
-            8 => {\r
-                write(cursor + 3, if read(cursor + 1, &code, modes[0], relative_base) == read(cursor + 2, &code, modes[1], relative_base) { 1 } else { 0 }, &mut code, modes[2], relative_base);\r
-                cursor += 4;\r
-            },\r
-\r
-            // Change relative base.\r
-            9 => {\r
-                relative_base += read(cursor + 1, &code, modes[0], relative_base);\r
-                cursor += 2;\r
-            }\r
-\r
-            99 => break,\r
-\r
-            _ => panic!("Unkown code: {}", code[cursor])\r
-        }\r
-    }\r
-    output\r
-}\r
-\r
-#[cfg(test)]\r
-mod tests {\r
-    use super::*;\r
-\r
-    #[test]\r
-    fn copy_of_itself() {\r
-        let c = [109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99];\r
-        let r = execute_op_code(&c, &Vec::new());\r
-        assert_eq!(r, c);\r
-    }\r
-\r
-    #[test]\r
-    fn output_big_number() {\r
-        let c = [1102,34_915_192,34_915_192,7,4,7,99,0];\r
-        let r = execute_op_code(&c, &Vec::new());\r
-        assert_eq!(r[0], 1_219_070_632_396_864);\r
-    }\r
-\r
-    #[test]\r
-    fn input_big_number() {\r
-        let c = [104,1_125_899_906_842_624,99];\r
-        let r = execute_op_code(&c, &Vec::new());\r
-        assert_eq!(r[0], 1_125_899_906_842_624);\r
-    }\r
-}
\ No newline at end of file
diff --git a/src/day11.rs b/src/day11.rs
new file mode 100644 (file)
index 0000000..e91d813
--- /dev/null
@@ -0,0 +1,116 @@
+use std::collections::HashMap;\r
+use super::intcode;\r
+\r
+enum NextCommand {\r
+    ColorToPaint,\r
+    Turn\r
+}\r
+\r
+struct Robot {\r
+    next_command: NextCommand,\r
+    current_pos: (i32, i32),\r
+    current_dir: i32, // 0: up, 1: right, 2: down, 3: left.\r
+    panels: HashMap<(i32, i32), i64>\r
+}\r
+\r
+impl Robot {\r
+    fn new() -> Self {\r
+        Robot {\r
+            next_command: NextCommand::ColorToPaint,\r
+            current_pos: (0, 0),\r
+            current_dir: 0,\r
+            panels: HashMap::new()\r
+        }\r
+    }\r
+}\r
+\r
+impl intcode::IO for Robot {\r
+    fn read(&mut self) -> i64 {\r
+        *self.panels.get(&self.current_pos).unwrap_or(&0)\r
+    }\r
+\r
+    fn write(&mut self, value: i64) {\r
+        self.next_command =\r
+            match self.next_command {\r
+                NextCommand::ColorToPaint => { self.panels.insert(self.current_pos, value); NextCommand::Turn },\r
+                NextCommand::Turn => {\r
+                    self.current_dir = (self.current_dir + if value == 0 { 3 } else { 1 }) % 4;\r
+                    self.current_pos =\r
+                        match self.current_dir {\r
+                            0 => (self.current_pos.0, self.current_pos.1 + 1),\r
+                            1 => (self.current_pos.0 + 1, self.current_pos.1),\r
+                            2 => (self.current_pos.0, self.current_pos.1 - 1),\r
+                            3 | _ => (self.current_pos.0 - 1, self.current_pos.1)\r
+                        };\r
+                    NextCommand::ColorToPaint\r
+                }\r
+            }\r
+    }\r
+}\r
+\r
+pub fn run_robot(code: &[i64], initial_value: i64) -> HashMap<(i32, i32), i64> {\r
+    let mut robot = Robot::new();\r
+    if initial_value != 0 {\r
+        robot.panels.insert((0, 0), initial_value);\r
+    }\r
+\r
+    intcode::execute_op_code_with_custom_io(code, &mut robot);\r
+    robot.panels\r
+}\r
+\r
+pub fn panels_to_layer(panels: &HashMap<(i32, i32), i64>) -> (Vec<u8>, usize) {\r
+    let coordinates: Vec<&(i32, i32)> = panels.keys().collect();\r
+    let min_x = coordinates.iter().min_by_key(|(x, _)| x).unwrap().0;\r
+    let max_x = coordinates.iter().max_by_key(|(x, _)| x).unwrap().0;\r
+    let min_y = coordinates.iter().min_by_key(|(_, y)| y).unwrap().1;\r
+    let max_y = coordinates.iter().max_by_key(|(_, y)| y).unwrap().1;\r
+\r
+    let width = (max_x - min_x) as usize + 1;\r
+    let height = (max_y - min_y) as usize + 1;\r
+\r
+    let mut layer = Vec::new();\r
+    layer.resize(width * height, 0);\r
+\r
+    for x in min_x ..= max_x {\r
+        for y in min_y ..= max_y {\r
+            let pos = (x - min_x) + ((height as i32 - y + min_y - 1) * width as i32); // Y axis is down.\r
+            layer[pos as usize] = *panels.get(&(x, y)).unwrap_or(&0) as u8;\r
+        }\r
+    }\r
+\r
+    (layer, width)\r
+}\r
+\r
+#[cfg(test)]\r
+mod tests {\r
+    use super::*;\r
+    use super::intcode::IO;\r
+\r
+    #[test]\r
+    fn part1() {\r
+        let mut robot = Robot::new();\r
+        robot.write(1); // Paint white.\r
+        robot.write(0); // Turn left.\r
+\r
+        robot.write(0); // Paint black.\r
+        robot.write(0); // Turn left.\r
+\r
+        robot.write(1); // Paint white.\r
+        robot.write(0); // Turn left.\r
+\r
+        robot.write(1); // Paint white.\r
+        robot.write(0); // Turn left.\r
+\r
+        robot.write(0); // Paint black.\r
+        robot.write(1); // Turn right.\r
+\r
+        robot.write(1); // Paint white.\r
+        robot.write(0); // Turn left.\r
+\r
+        robot.write(1); // Paint white.\r
+        robot.write(0); // Turn left.\r
+\r
+        assert_eq!(robot.panels.len(), 6);\r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/src/intcode.rs b/src/intcode.rs
new file mode 100644 (file)
index 0000000..b1968ac
--- /dev/null
@@ -0,0 +1,202 @@
+#[derive(Copy, Clone, Debug)]\r
+enum Mode {\r
+    Position,\r
+    Immediate,\r
+    Relative\r
+}\r
+\r
+pub trait IO {\r
+    fn read(&mut self) -> i64;\r
+    fn write(&mut self, value: i64);\r
+}\r
+\r
+struct Buffer {\r
+    output: Vec<i64>,\r
+    input: Vec<i64>\r
+}\r
+\r
+impl Buffer {\r
+    fn from(input: &[i64]) -> Self {\r
+        Buffer {\r
+            output: Vec::new(),\r
+            input: Vec::from(input)\r
+        }\r
+    }\r
+}\r
+\r
+impl IO for Buffer {\r
+    fn read(&mut self) -> i64 {\r
+        self.input.remove(0)\r
+    }\r
+\r
+    fn write(&mut self, value: i64) {\r
+        self.output.push(value)\r
+    }\r
+}\r
+\r
+// 'true' -> immediate mode, 'false' -> position mode.\r
+fn read_op_and_modes(mut code: i64) -> (i64, [Mode; 3]) {\r
+    let mut modes: [Mode; 3] = [ Mode::Position, Mode::Position, Mode::Position ];\r
+\r
+    for i in (2..=4).rev() {\r
+        let power = 10i64.pow(i);\r
+        if code >= 2 * power {\r
+            modes[i as usize - 2] = Mode::Relative;\r
+            code -= 2 * power;\r
+        } else if code >= power {\r
+            modes[i as usize - 2] = Mode::Immediate;\r
+            code -= power;\r
+        }\r
+    }\r
+\r
+    (code, modes)\r
+}\r
+\r
+pub fn execute_op_code(code: &[i64], input: &[i64]) -> Vec<i64> {\r
+    let mut buffer = Buffer::from(input);\r
+    execute_op_code_with_custom_io(code, &mut buffer);\r
+    buffer.output\r
+}\r
+\r
+pub fn execute_op_code_with_custom_io(code: &[i64], io: &mut dyn IO) {\r
+    let mut code = Vec::from(code);\r
+    let mut cursor = 0;\r
+    let mut relative_base = 0;\r
+\r
+    fn read(position: usize, code: &[i64], mode: Mode, relative_base: i64) -> i64 {\r
+        if position >= code.len() { return 0 }\r
+\r
+        match mode {\r
+            Mode::Position => if code[position] as usize >= code.len() { 0 } else { code[code[position] as usize] },\r
+            Mode::Immediate => code[position],\r
+            Mode::Relative => if (code[position] + relative_base) as usize >= code.len() { 0 } else { code[(code[position] + relative_base) as usize] }\r
+        }\r
+    };\r
+\r
+    fn write(position: usize, value: i64, code: &mut Vec<i64>, mode: Mode, relative_base: i64) {\r
+        let ref_position =\r
+            match mode {\r
+                Mode::Position => code[position] as usize,\r
+                Mode::Immediate => panic!("Can't write un immediate mode"),\r
+                Mode::Relative => (code[position] + relative_base) as usize\r
+            };\r
+\r
+        if ref_position >= code.len() {\r
+            code.resize(ref_position + 1, 0);\r
+        }\r
+\r
+        code[ref_position] = value;\r
+    }\r
+\r
+    fn jump_if(cond: bool, cursor: usize, code: &[i64], modes: [Mode; 3], relative_base: i64) -> usize {\r
+        let value = read(cursor + 1, &code, modes[0], relative_base);\r
+        if cond == (value != 0) {\r
+            read(cursor + 2, &code, modes[1], relative_base) as usize\r
+        } else {\r
+            cursor + 3\r
+        }\r
+    };\r
+\r
+    loop {\r
+        let (op, modes) = read_op_and_modes(code[cursor]);\r
+\r
+        match op {\r
+            // Sum.\r
+            1 => {\r
+                write(cursor + 3, read(cursor + 1, &code, modes[0], relative_base) + read(cursor + 2, &code, modes[1], relative_base), &mut code, modes[2], relative_base);\r
+                cursor += 4;\r
+            },\r
+\r
+            // Multiply.\r
+            2 => {\r
+                write(cursor + 3, read(cursor + 1, &code, modes[0], relative_base) * read(cursor + 2, &code, modes[1], relative_base), &mut code, modes[2], relative_base);\r
+                cursor += 4;\r
+            },\r
+\r
+            // Input.\r
+            3 => {\r
+                write(cursor + 1, io.read(), &mut code, modes[0], relative_base);\r
+                cursor += 2;\r
+            }\r
+\r
+            // Output.\r
+            4 => {\r
+                io.write(read(cursor + 1, &code, modes[0], relative_base));\r
+                cursor += 2;\r
+            }\r
+\r
+            // Jump-if-true.\r
+            5 => cursor = jump_if(true, cursor, &code, modes, relative_base),\r
+\r
+            // Jump-if-false.\r
+            6 => cursor = jump_if(false, cursor, &code, modes, relative_base),\r
+\r
+            // Less than.\r
+            7 => {\r
+                write(cursor + 3, if read(cursor + 1, &code, modes[0], relative_base) < read(cursor + 2, &code, modes[1], relative_base) { 1 } else { 0 }, &mut code, modes[2], relative_base);\r
+                cursor += 4;\r
+            },\r
+\r
+            // Equals.\r
+            8 => {\r
+                write(cursor + 3, if read(cursor + 1, &code, modes[0], relative_base) == read(cursor + 2, &code, modes[1], relative_base) { 1 } else { 0 }, &mut code, modes[2], relative_base);\r
+                cursor += 4;\r
+            },\r
+\r
+            // Change relative base.\r
+            9 => {\r
+                relative_base += read(cursor + 1, &code, modes[0], relative_base);\r
+                cursor += 2;\r
+            }\r
+\r
+            99 => break,\r
+\r
+            _ => panic!("Unknown code: {}", code[cursor])\r
+        }\r
+    }\r
+}\r
+\r
+#[cfg(test)]\r
+mod tests_day05 {\r
+    use super::*;\r
+\r
+    #[test]\r
+    fn part2() {\r
+        let c = [3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99];\r
+\r
+        let r1 = execute_op_code(&c, &[7]);\r
+        assert_eq!(r1[0], 999);\r
+\r
+        let r2 = execute_op_code(&c, &[8]);\r
+        assert_eq!(r2[0], 1000);\r
+\r
+        let r3 = execute_op_code(&c, &[9]);\r
+        assert_eq!(r3[0], 1001);\r
+    }\r
+}\r
+\r
+#[cfg(test)]\r
+mod tests_day09 {\r
+    use super::*;\r
+\r
+    #[test]\r
+    fn copy_of_itself() {\r
+        let c = [109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99];\r
+        let r = execute_op_code(&c, &Vec::new());\r
+        assert_eq!(r, c);\r
+    }\r
+\r
+    #[test]\r
+    fn output_big_number() {\r
+        let c = [1102,34_915_192,34_915_192,7,4,7,99,0];\r
+        let r = execute_op_code(&c, &Vec::new());\r
+        assert_eq!(r[0], 1_219_070_632_396_864);\r
+    }\r
+\r
+    #[test]\r
+    fn input_big_number() {\r
+        let c = [104,1_125_899_906_842_624,99];\r
+        let r = execute_op_code(&c, &Vec::new());\r
+        assert_eq!(r[0], 1_125_899_906_842_624);\r
+    }\r
+}
\ No newline at end of file
index 42699c7..99ea6e0 100644 (file)
@@ -2,15 +2,15 @@ use std::env;
 use std::fs;
 use std::time::Instant;
 
+mod common;
+mod intcode;
 mod day01;
 mod day02;
 mod day03;
-mod day05;
 mod day06;
 mod day07;
 mod day08;
-mod day09;
-mod common;
+mod day11;
 
 fn day01() -> String {
     let masses = common::read_list_of_numbers("data/day01.input", "\n");
@@ -38,7 +38,7 @@ fn day04() -> String {
 
 fn day05() -> String {
     let code = common::read_list_of_numbers("data/day05.input", ",");
-    format!("part1: {:?}, part2: {:?}", day05::execute_op_code(&mut Vec::from(&code[..]), &[1]), day05::execute_op_code(&mut Vec::from(&code[..]), &[5]))
+    format!("part1: {:?}, part2: {:?}", intcode::execute_op_code(&code, &[1]), intcode::execute_op_code(&code, &[5]))
 }
 
 fn day06() -> String {
@@ -61,12 +61,25 @@ fn day08() -> String {
     let layer = day08::layer_with_fewer_0(&layers[..]);
     let merged = day08::merge_layers(&layers[..]);
 
-    format!("part1: {}, part2:\n{}", day08::one_digits_times_two_digits(layer), day08::layer_to_printable_string(&merged, 25))
+    format!("part1: {}, part2:\n{}", day08::one_digits_times_two_digits(layer), common::layer_to_printable_string(&merged, 25))
 }
 
 fn day09() -> String {
     let code = common::read_list_of_numbers::<&str, i64>("data/day09.input", ",");
-    format!("part1: {:?}, part2: {:?}", day09::execute_op_code(&code, &[1]), day09::execute_op_code(&code, &[2]))
+
+    format!("part1: {:?}, part2: {:?}", intcode::execute_op_code(&code, &[1]), intcode::execute_op_code(&code, &[2]))
+}
+
+fn day10() -> String {
+    format!("")
+}
+
+fn day11() -> String {
+    let code = common::read_list_of_numbers::<&str, i64>("data/day11.input", ",");
+    let panels = day11::run_robot(&code, 1);
+    let (layer, width) = day11::panels_to_layer(&panels);
+
+    format!("part1: {:?}, part2:\n{}", day11::run_robot(&code, 0).len(), common::layer_to_printable_string(&layer, width))
 }
 
 fn format_micros(t: u128) -> String {
@@ -96,7 +109,9 @@ fn main() {
         day06,
         day07,
         day08,
-        day09
+        day09,
+        day10,
+        day11
     );
 
     let args: Vec<String> = env::args().skip(1).collect();