Day 7 part 2
authorGrégory Burri <gregory.burri@matisa.ch>
Fri, 13 Dec 2019 16:00:15 +0000 (17:00 +0100)
committerGrégory Burri <gregory.burri@matisa.ch>
Fri, 13 Dec 2019 16:00:15 +0000 (17:00 +0100)
src/day07.rs
src/main.rs

index fea25ff..9c249e6 100644 (file)
+use super::intcode;\r
+use itertools::Itertools;\r
+use std::sync::mpsc::{ self, Sender, Receiver };\r
+use std::thread::{ self, JoinHandle };\r
 \r
+fn last_thruster_signal(code: &[i64], phase_setting: &[i64]) -> i64 {\r
+    phase_setting.iter().fold(0, |last_output, input| intcode::execute_op_code(&code, &[*input, last_output])[0])\r
+}\r
 \r
+pub fn find_largest_last_thruster_signal(code: &[i64]) -> i64 {\r
+    (0i64 ..= 4i64).permutations(5).map(|phase_setting| last_thruster_signal(&code, &phase_setting)).max().unwrap()\r
+}\r
+\r
+struct Stage {\r
+    input_channel: mpsc::Receiver<i64>,\r
+    output_channel: mpsc::Sender<i64>,\r
+    last_produced_value: i64\r
+}\r
+\r
+impl Stage {\r
+    fn new(input_channel: mpsc::Receiver<i64>, output_channel: mpsc::Sender<i64>) -> Self {\r
+        Stage { input_channel, output_channel, last_produced_value: 0 }\r
+    }\r
+}\r
+\r
+impl intcode::IO for Stage {\r
+    // May block.\r
+    fn read(&mut self) -> i64 {\r
+        match self.input_channel.recv() {\r
+            Ok(value) => value,\r
+            Err(_) => 0\r
+        }\r
+    }\r
+\r
+    // Send to the output channel.\r
+    fn write(&mut self, value: i64) {\r
+        self.last_produced_value = value;\r
+        self.output_channel.send(value);\r
+    }\r
+}\r
+\r
+fn last_thruster_signal_with_feedback_loop(code: &[i64], phase_setting: &[i64]) -> i64 {\r
+    let n = phase_setting.len();\r
+\r
+    let mut senders = Vec::<Sender<i64>>::new();\r
+    let mut receivers = Vec::<Receiver<i64>>::new();\r
+\r
+    for (i, (s, r)) in (0 .. n).map(|i| (i, mpsc::channel::<i64>())) {\r
+        // Initial values.\r
+        s.send(phase_setting[i]);\r
+        if i == 0 { s.send(0); }\r
+\r
+        senders.insert(if i == 0 { 0 } else { i - 1 }, s);\r
+        receivers.push(r);\r
+    }\r
+\r
+    // Prepare each pair of received and sender for the each stages.\r
+    let mut channels: Vec<(Receiver<i64>, Sender<i64>)> = receivers.drain(..).zip(senders.drain(..)).collect();\r
+\r
+    let mut join_handles: Vec<JoinHandle<i64>> =\r
+        channels\r
+            .drain(..)\r
+            .map(\r
+                |(receiver, sender)| {\r
+                    let code_copy = Vec::<i64>::from(code);\r
+                    thread::spawn(\r
+                        move || {\r
+                            let mut stage = Stage::new(receiver, sender);\r
+                            intcode::execute_op_code_with_custom_io(&code_copy, &mut stage);\r
+                            stage.last_produced_value\r
+                        }\r
+                    )\r
+                }\r
+            )\r
+            .collect();\r
+\r
+    join_handles.pop().unwrap().join().unwrap()\r
+}\r
+\r
+pub fn find_largest_last_thruster_signal_with_feedback_loop(code: &[i64]) -> i64 {\r
+    (5i64 ..= 9i64).permutations(5).map(|phase_setting| last_thruster_signal_with_feedback_loop(&code, &phase_setting)).max().unwrap()\r
+}\r
 \r
 #[cfg(test)]\r
 mod tests {\r
+    use super::*;\r
 \r
     #[test]\r
-    fn part1 () {\r
+    fn part1_sample_1() {\r
+        let code = vec![3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0];\r
+        let phase_setting = [4,3,2,1,0];\r
+        assert_eq!(last_thruster_signal(&code, &phase_setting), 43210);\r
+    }\r
 \r
+    #[test]\r
+    fn part1_sample_2() {\r
+        let code = vec![3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0];\r
+        let phase_setting = [0,1,2,3,4];\r
+        assert_eq!(last_thruster_signal(&code, &phase_setting), 54321);\r
+    }\r
+\r
+    #[test]\r
+    fn part1_sample_3() {\r
+        let code = vec![3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0];\r
+        let phase_setting = [1,0,4,3,2];\r
+        assert_eq!(last_thruster_signal(&code, &phase_setting), 65210);\r
+    }\r
+\r
+    #[test]\r
+    fn part2_sample_1() {\r
+        let code = vec![3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5];\r
+        let phase_setting = [9,8,7,6,5];\r
+        assert_eq!(last_thruster_signal_with_feedback_loop(&code, &phase_setting), 139_629_729);\r
+    }\r
+\r
+    #[test]\r
+    fn part2_sample_2() {\r
+        let code = vec![3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10];\r
+        let phase_setting = [9,7,8,5,6];\r
+        assert_eq!(last_thruster_signal_with_feedback_loop(&code, &phase_setting), 18216);\r
     }\r
 }
\ No newline at end of file
index 2d8398f..e8266af 100644 (file)
@@ -50,7 +50,9 @@ fn day06() -> String {
 }
 
 fn day07() -> String {
-    format!("")
+    let code = common::read_list_of_numbers("data/day07.input", ",");
+
+    format!("part1: {}, part2: {}", day07::find_largest_last_thruster_signal(&code), day07::find_largest_last_thruster_signal_with_feedback_loop(&code))
 }
 
 fn day08() -> String {
@@ -122,9 +124,11 @@ fn main() {
 
     // No argument -> execute all day problems.
     if args.is_empty() {
-        for i in 1..=days.len() {
+        let now = Instant::now();
+        for i in 1 ..= days.len() {
             do_day(&days, i)
         }
+        println!("Time to execute all days: {}", format_micros(now.elapsed().as_micros()));
     } else {
         for arg in args {
             let day = arg.parse::<usize>().unwrap();