/ day17 / src / main.rs
main.rs
  1  use std::{
  2      thread::{self, sleep},
  3      time::Duration,
  4  };
  5  
  6  #[derive(Debug)]
  7  pub struct Computer {
  8      pub reg_a: u128,
  9      pub reg_b: u128,
 10      pub reg_c: u128,
 11      pub ip: i128,
 12      pub output: Vec<u8>,
 13  }
 14  
 15  impl Computer {
 16      fn end(&self) -> String {
 17          return format!(
 18              "{}",
 19              self.output
 20                  .iter()
 21                  .map(|n| n.to_string())
 22                  .collect::<Vec<String>>()
 23                  .join(",")
 24          );
 25      }
 26  
 27      fn adv(&mut self, val: u128) {
 28          self.reg_a /= 2u128.pow(val as u32);
 29      }
 30  
 31      fn bxl(&mut self, val: u128) {
 32          self.reg_b ^= val;
 33      }
 34  
 35      fn bst(&mut self, val: u128) {
 36          self.reg_b = val % 8;
 37      }
 38  
 39      fn jnz(&mut self, val: u128) {
 40          if self.reg_a != 0 {
 41              self.ip = val as i128 - 2;
 42          }
 43      }
 44  
 45      fn bxc(&mut self, _val: u128) {
 46          self.reg_b ^= self.reg_c;
 47      }
 48  
 49      fn out(&mut self, val: u128) {
 50          self.output.push((val % 8) as u8);
 51      }
 52  
 53      fn bdv(&mut self, val: u128) {
 54          self.reg_b = self.reg_a / 2u128.pow(val as u32);
 55      }
 56  
 57      fn cdv(&mut self, val: u128) {
 58          self.reg_c = self.reg_a / 2u128.pow(val as u32);
 59      }
 60  
 61      fn exec(&mut self, i: u8, val: u128) {
 62          let real_val: u128;
 63          if [0, 2, 5, 6, 7].contains(&i) {
 64              match val {
 65                  0 | 1 | 2 | 3 => real_val = val,
 66                  4 => real_val = self.reg_a,
 67                  5 => real_val = self.reg_b,
 68                  6 => real_val = self.reg_c,
 69                  _ => todo!(),
 70              }
 71          } else {
 72              real_val = val;
 73          }
 74          match i {
 75              0 => self.adv(real_val),
 76              1 => self.bxl(real_val),
 77              2 => self.bst(real_val),
 78              3 => self.jnz(real_val),
 79              4 => self.bxc(real_val),
 80              5 => self.out(real_val),
 81              6 => self.bdv(real_val),
 82              7 => self.cdv(real_val),
 83              _ => todo!(),
 84          }
 85      }
 86  }
 87  
 88  fn main() {
 89      let input: Vec<&str> = std::str::from_utf8(include_bytes!("input"))
 90          .unwrap()
 91          .split("\n\n")
 92          .collect();
 93      let registers: Vec<u128> = input[0]
 94          .lines()
 95          .map(|l| l.split(" ").last().unwrap().parse::<u128>().unwrap())
 96          .collect();
 97      let instructions: Vec<u8> = input[1]
 98          .trim()
 99          .split(" ")
100          .last()
101          .unwrap()
102          .split(",")
103          .map(|i| i.parse::<u8>().unwrap())
104          .collect();
105  
106      let mut computer = Computer {
107          reg_a: registers[0],
108          reg_b: registers[1],
109          reg_c: registers[2],
110          ip: 0,
111          output: vec![],
112      };
113      while (computer.ip as usize) < instructions.len() {
114          computer.exec(
115              instructions[computer.ip as usize],
116              instructions[computer.ip as usize + 1] as u128,
117          );
118          computer.ip += 2;
119          if (computer.ip as usize) >= instructions.len() {
120              break;
121          }
122      }
123      println!("Part 1: {}", computer.end());
124  
125      // Part 2 (ONLY WORKS FOR MY INPUT)
126      let mut threads: Vec<thread::JoinHandle<()>> = vec![];
127      for _i in 0..8 {
128          let input: Vec<&str> = std::str::from_utf8(include_bytes!("input"))
129              .unwrap()
130              .split("\n\n")
131              .collect();
132          let registers: Vec<u128> = input[0]
133              .lines()
134              .map(|l| l.split(" ").last().unwrap().parse::<u128>().unwrap())
135              .collect();
136          let instructions: Vec<u8> = input[1]
137              .trim()
138              .split(" ")
139              .last()
140              .unwrap()
141              .split(",")
142              .map(|i| i.parse::<u8>().unwrap())
143              .collect();
144          let b = registers[1];
145          let c = registers[2];
146          threads.push(thread::spawn(move || {
147              let mut __i = _i;
148              let result = 'new_i: loop {
149                  __i += 8;
150                  let i = 7 + (1 + (0 + (6 + (3 + (2 + __i * 8) * 8) * 8) * 8) * 8) * 8;
151                  let mut computer = Computer {
152                      reg_a: i,
153                      reg_b: b,
154                      reg_c: c,
155                      ip: 0,
156                      output: vec![],
157                  };
158                  while (computer.ip as usize) < instructions.len() {
159                      computer.exec(
160                          instructions[computer.ip as usize],
161                          instructions[computer.ip as usize + 1] as u128,
162                      );
163                      computer.ip += 2;
164                      if (computer.ip as usize) >= instructions.len() {
165                          break;
166                      }
167                      for (index, n) in computer.output.iter().enumerate() {
168                          if instructions[index] != *n {
169                              continue 'new_i;
170                          }
171                      }
172                      if computer.output.len() > instructions.len() {
173                          continue 'new_i;
174                      }
175                  }
176                  if computer.output == instructions {
177                      break i;
178                  }
179              };
180              println!("Part 2: {result}");
181          }));
182      }
183      loop {
184          sleep(Duration::from_secs(1));
185      }
186  }