use regex::Regex; use std::fmt; #[derive(Clone)] struct Device { a: u64, b: u64, c: u64, program: Vec, ip: usize, output: Vec, } 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 = 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::>() .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 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::(), 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); }