diff options
-rw-r--r-- | 2024_rust/inputs/17 | 5 | ||||
-rw-r--r-- | 2024_rust/src/bin/day17.rs | 179 |
2 files changed, 184 insertions, 0 deletions
diff --git a/2024_rust/inputs/17 b/2024_rust/inputs/17 new file mode 100644 index 0000000..02a6fbe --- /dev/null +++ b/2024_rust/inputs/17 @@ -0,0 +1,5 @@ +Register A: 64751475 +Register B: 0 +Register C: 0 + +Program: 2,4,1,2,7,5,4,5,1,3,5,5,0,3,3,0 diff --git a/2024_rust/src/bin/day17.rs b/2024_rust/src/bin/day17.rs new file mode 100644 index 0000000..6c9bf1a --- /dev/null +++ b/2024_rust/src/bin/day17.rs @@ -0,0 +1,179 @@ +use regex::Regex; +use std::fmt; + +#[derive(Clone)] +struct Device { + a: u64, + b: u64, + c: u64, + program: Vec<u8>, + ip: usize, + output: Vec<u8>, +} + +impl Device { + fn parse(input: &str) -> Device { + let mut a: u64 = 0; + let mut b: u64 = 0; + let mut c: u64 = 0; + let mut program: Vec<u8> = vec![]; + let re = Regex::new(r"Register ([ABC]): ([0-9]+)|Program: ([0-9,]+)").unwrap(); + for cap in re.captures_iter(input) { + if let Some(opcodes) = cap.get(3) { + program = opcodes + .as_str() + .split(",") + .map(|op| op.parse().unwrap()) + .collect(); + continue; + } else { + match &cap[1] { + "A" => a = cap[2].parse().unwrap(), + "B" => b = cap[2].parse().unwrap(), + "C" => c = cap[2].parse().unwrap(), + _ => unreachable!(), + } + } + } + Device { + a, + b, + c, + program, + ip: 0, + output: vec![], + } + } + + fn instruction(&self) -> Option<(Instruction, u8)> { + if self.ip < self.program.len() { + Some((self.program[self.ip].into(), self.program[self.ip + 1])) + } else { + None + } + } + + fn read_next_instruction(&mut self) -> Option<(Instruction, u8)> { + let res = self.instruction(); + if res.is_some() { + self.ip += 2; + } + res + } + + fn get_combo(&self, op: u8) -> u64 { + match op { + 0..=3 => op as u64, + 4 => self.a, + 5 => self.b, + 6 => self.c, + _ => unimplemented!(), + } + } + + fn output(&self) -> String { + self.output + .iter() + .map(|n| format!("{}", n)) + .collect::<Vec<_>>() + .join(",") + } + + fn step(&mut self) -> bool { + // println!("{}", self); + let Some((instruction, operand)) = self.read_next_instruction() else { + return false; + }; + match instruction { + Adv => self.a /= 2u64.pow(self.get_combo(operand) as u32), + Bxl => self.b ^= operand as u64, + Bst => self.b = self.get_combo(operand) % 8, + Jnz => { + if self.a != 0 { + self.ip = operand as usize; + } + } + Bxc => self.b ^= self.c, + Out => self.output.push((self.get_combo(operand) % 8) as u8), + Bdv => self.b = self.a / 2u64.pow(self.get_combo(operand) as u32), + Cdv => self.c = self.a / 2u64.pow(self.get_combo(operand) as u32), + }; + true + } + + fn run(&mut self) -> String { + while self.step() {} + self.output() + } +} + +#[derive(Debug)] +enum Instruction { + Adv, + Bxl, + Bst, + Jnz, + Bxc, + Out, + Bdv, + Cdv, +} +use Instruction::*; + +impl From<u8> for Instruction { + fn from(item: u8) -> Instruction { + match item { + 0 => Adv, + 1 => Bxl, + 2 => Bst, + 3 => Jnz, + 4 => Bxc, + 5 => Out, + 6 => Bdv, + 7 => Cdv, + _ => panic!(), + } + } +} + +impl fmt::Display for Device { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "Registers: A={} B={} C={}", self.a, self.b, self.c)?; + writeln!(f, "{:?}", self.program)?; + let spaces = 1 + 3 * self.ip; + let curri = match self.instruction() { + Some((i, op)) => { + let combo = self.get_combo(op); + if op < 4 { + format!(" {i:?}({op})") + } else { + format!(" {i:?}({op}) (combo: {combo})") + } + } + None => "".to_string(), + }; + writeln!( + f, + "{}^{}", + (0..spaces).map(|_| " ").collect::<String>(), + curri + )?; + writeln!(f, "Output: {:?}", self.output()) + } +} + +fn p1(input: &str) -> String { + let mut dev = Device::parse(input); + let result = dev.run(); + result.to_string() +} + +fn p2(_input: &str) -> String { + let result = "TODO"; + + result.to_string() +} + +fn main() { + aoc2024::run_day("17", p1, p2); +} |