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); +} | 
