Untitled

 avatar
unknown
rust
4 months ago
5.6 kB
14
Indexable
pub fn solution(test: bool) -> ((usize, Duration), (usize, Duration)) {
    let lines;
    if test {
        lines = include_str!("../../../AdventOfCodeInputs/problem_inputs_2024/day_17_test.txt");
    } else {
        lines = include_str!("../../../AdventOfCodeInputs/problem_inputs_2024/day_17.txt");
    }
    (solve01(lines), solve02(lines))
}

fn solve01(lines: &str) -> (usize, Duration) {
    let now = Instant::now();
    let mut comp = Computer::from_str(lines);
    println!(
        "Part 1: '{}' computed in {:?}",
        comp.run().iter().map(|f| f.to_string()).join(","),
        now.elapsed()
    );
    (0, now.elapsed())
}

fn solve02(lines: &str) -> (usize, Duration) {
    let now = Instant::now();
    let comp = Computer::from_str(lines);
    let mut a: usize = 0;
    let mut ind = comp.rom.len() - 1;
    loop {
        let mut comp_try = Computer {
            registers: [a as isize, 0, 0],
            ip: 0,
            rom: comp.rom.clone(),
        };
        let mut output = comp_try.run();
        while output.len() < comp.rom.len() {
            output.push(isize::MAX);
        }
        if output[ind..] == comp.rom[ind..] {
            if ind == 0 {
                break;
            } else {
                ind -= 1;
            }
        } else {
            a += 8_usize.pow(ind as u32);
        }
    }
    let mut sanity = Computer {
        registers: [a as isize, 0, 0],
        ip: 0,
        rom: comp.rom.clone(),
    };
    assert_eq!(sanity.run(), comp.rom);
    (a, now.elapsed())
}
#[derive(Debug, Clone, Copy)]
enum Instruction {
    Adv,
    Bxl,
    Bst,
    Jnz,
    Bxc,
    Out,
    Bdv,
    Cdv,
}

impl Instruction {
    fn from_int(i: u32) -> Self {
        match i {
            0 => Self::Adv,
            1 => Self::Bxl,
            2 => Self::Bst,
            3 => Self::Jnz,
            4 => Self::Bxc,
            5 => Self::Out,
            6 => Self::Bdv,
            7 => Self::Cdv,
            _ => panic!("Invalid instruction"),
        }
    }
}

#[derive(Debug, Clone)]
struct Computer {
    registers: [isize; 3],
    ip: usize,
    rom: Vec<isize>,
}

impl Computer {
    fn from_str(lines: &str) -> Self {
        let mut registers = [0; 3];
        let ip = 0;
        let rom;
        let mut lines = lines.lines();
        for i in 0..3 {
            registers[i] = lines
                .next()
                .unwrap()
                .split(':')
                .nth(1)
                .unwrap()
                .trim()
                .parse()
                .unwrap();
        }
        lines.next();
        rom = lines
            .next()
            .unwrap()
            .split(": ")
            .nth(1)
            .unwrap()
            .split(',')
            .map(|c| c.parse().unwrap())
            .collect();
        Self { registers, ip, rom }
    }

    fn get_register_value(&self, register: usize) -> isize {
        self.registers[register]
    }

    fn run(&mut self) -> Vec<isize> {
        let mut ans = Vec::new();
        while self.ip < self.rom.len() - 1 {
            if let Some(output) = self.step() {
                ans.push(output);
            }
        }
        ans
    }

    fn step(&mut self) -> Option<isize> {
        let instr = Instruction::from_int(self.rom[self.ip] as u32);
        let operand = self.rom[self.ip + 1];
        let out = self.apply_instr(instr, operand as usize);
        return out;
    }

    fn parse_combo(&self, combo: usize) -> usize {
        match combo {
            0..=3 => combo,
            4..=6 => self.get_register_value(combo - 4) as usize,
            _ => panic!("Invalid operand"),
        }
    }

    fn apply_instr(&mut self, instr: Instruction, operand: usize) -> Option<isize> {
        match instr {
            Instruction::Adv => {
                let numerator = self.get_register_value(0);
                let operand = self.parse_combo(operand);
                self.registers[0] = numerator >> operand;
                self.ip += 2;
            }
            Instruction::Bxl => {
                let x = self.get_register_value(1);
                self.registers[1] = x ^ operand as isize;
                self.ip += 2;
            }
            Instruction::Bst => {
                let x = self.parse_combo(operand);
                self.registers[1] = (x % 8) as isize;
                self.ip += 2;
            }
            Instruction::Jnz => {
                if self.get_register_value(0) != 0 {
                    self.ip = operand;
                } else {
                    self.ip += 2;
                }
            }
            Instruction::Bxc => {
                let b = self.get_register_value(1);
                let c = self.get_register_value(2);
                self.registers[1] = b ^ c;
                self.ip += 2;
            }
            Instruction::Out => {
                let x = self.parse_combo(operand);
                self.ip += 2;
                return Some((x % 8) as isize);
            }
            Instruction::Bdv => {
                let numerator = self.get_register_value(0);
                let operand = self.parse_combo(operand);
                self.registers[1] = numerator >> operand;
                self.ip += 2;
            }
            Instruction::Cdv => {
                let numerator = self.get_register_value(0);
                let operand = self.parse_combo(operand);
                self.registers[2] = numerator >> operand;
                self.ip += 2;
            }
        }
        None
    }
}
Editor is loading...
Leave a Comment