From e71a3bde6f7d2dfd0cb162eeec080c6d56b1ed64 Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Wed, 18 Dec 2024 09:13:33 -0500 Subject: [PATCH] wip star thirty four --- src/main.rs | 2 + src/star_thirty_four.rs | 332 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 334 insertions(+) create mode 100644 src/star_thirty_four.rs diff --git a/src/main.rs b/src/main.rs index cdfdf96..a54e194 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,7 @@ mod star_thirty; mod star_thirty_one; mod star_thirty_two; mod star_thirty_three; +mod star_thirty_four; fn main() { let args: Vec = env::args().collect(); @@ -70,6 +71,7 @@ fn main() { "31" => star_thirty_one::run(), "32" => star_thirty_two::run(), "33" => star_thirty_three::run(), + "34" => star_thirty_four::run(), _ => unreachable!(), } } diff --git a/src/star_thirty_four.rs b/src/star_thirty_four.rs new file mode 100644 index 0000000..cf06be8 --- /dev/null +++ b/src/star_thirty_four.rs @@ -0,0 +1,332 @@ +use std::fs; + +pub fn run() { + let file = fs::read_to_string("./inputs/star_thirty_four.txt").unwrap(); + let cpu = parse_input(file.lines()); + let result = fix_corrupted_program(&cpu); + + println!("Result: {}", result); +} + +#[derive(PartialEq, Debug, Clone)] +struct Registers { + a: isize, + b: isize, + c: isize, + pc: usize, +} + +#[derive(PartialEq, Debug, Clone)] +struct CPU { + registers: Registers, + halted: bool, + halt_if_different: bool, + program: Vec, + output: Vec, +} + +impl CPU { + pub fn new() -> Self { + Self { + halted: false, + halt_if_different: false, + program: vec![], + output: vec![], + registers: Registers { + a: 0, + b: 0, + c: 0, + pc: 0, + } + } + } + + pub fn run(&mut self) { + while !self.halted { + self.tick(); + } + } + + fn tick(&mut self) { + if self.registers.pc >= self.program.len() { + self.halted = true; + return; + } + self.decode(); + } + + fn decode(&mut self) { + let opcode = *self.program.get(self.registers.pc).unwrap_or(&0); + match opcode { + 0 => self.adv(), + 1 => self.bxl(), + 2 => self.bst(), + 3 => self.jnz(), + 4 => self.bxc(), + 5 => self.out(), + 6 => self.bdv(), + 7 => self.cdv(), + _ => unreachable!(), + } + } + + fn parse_operand(&self, operand: u8, is_literal: bool) -> isize { + if is_literal { + return operand as isize; + } + match operand { + 4 => self.registers.a, + 5 => self.registers.b, + 6 => self.registers.c, + _ => operand as isize, + } + } + + fn adv(&mut self) { + let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false); + self.registers.a = self.registers.a / 2_isize.pow(operand as u32); + self.registers.pc += 2; + } + + fn bxl(&mut self) { + let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), true); + self.registers.b = self.registers.b ^ operand; + self.registers.pc += 2; + } + + fn bst(&mut self) { + let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false); + self.registers.b = operand & 0b111; + self.registers.pc += 2; + } + + fn jnz(&mut self) { + let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), true); + if self.registers.a == 0 { + self.registers.pc += 2; + return + } + self.registers.pc = operand as usize & 0b111; + } + + fn bxc(&mut self) { + self.registers.b = self.registers.b ^ self.registers.c; + self.registers.pc += 2; + } + + fn out(&mut self) { + let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false); + let result = operand & 0b111; + self.output.push(result); + if self.halt_if_different { + if result != self.program[self.output.len() - 1] as isize { + self.halted = true; + } + } + self.registers.pc += 2; + } + + fn bdv(&mut self) { + let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false); + self.registers.b = self.registers.a / 2_isize.pow(operand as u32); + self.registers.pc += 2; + } + + fn cdv(&mut self) { + let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false); + self.registers.c = self.registers.a / 2_isize.pow(operand as u32); + self.registers.pc += 2; + } +} + +fn parse_input<'a, I>(str_lines: I) -> CPU +where + I: IntoIterator +{ + let mut cpu = CPU::new(); + + for str_line in str_lines { + let l = str_line.to_string(); + if l.starts_with("Register A:") { + cpu.registers.a = parse_register_data(&l); + } else if l.starts_with("Register B:") { + cpu.registers.b = parse_register_data(&l); + } else if l.starts_with("Register C:") { + cpu.registers.c = parse_register_data(&l); + } else if l.starts_with("Program:") { + cpu.program = parse_program(&l) + } + } + + cpu +} + +fn parse_register_data(str_line: &String) -> isize { + str_line[12..].to_string().trim().parse().unwrap() +} + +fn parse_program(str_line: &String) -> Vec { + str_line[8..].to_string() + .trim() + .split(",") + .map(|b| b.trim().parse::().unwrap()) + .collect() +} + +fn fix_corrupted_program(cpu: &CPU) -> isize { + let mut current_a = 0; + let mut cpu_copy = cpu.clone(); + cpu_copy.halt_if_different = false; + loop { + if current_a == cpu.registers.a { + current_a += 1; + continue; + } + cpu_copy.registers.a = current_a; + cpu_copy.registers.b = cpu.registers.b; + cpu_copy.registers.c = cpu.registers.c; + cpu_copy.registers.pc = 0; + cpu_copy.halted = false; + cpu_copy.output = vec![]; + cpu_copy.run(); + if cpu_copy.program.len() != cpu_copy.output.len() { + current_a += 1; + continue; + } + let mut is_match = true; + for (p, o) in cpu_copy.program.iter().zip(cpu_copy.output.iter()) { + if *p as isize != *o { + is_match = false; + break; + } + } + if !is_match { + current_a += 1; + continue; + } + return current_a; + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_input() { + let input = String::from("\ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 +" + ); + let cpu = parse_input(input.lines()); + let expected_cpu = CPU { + halted: false, + halt_if_different: false, + program: vec![0, 1, 5, 4, 3, 0], + output: vec![], + registers: Registers { + a: 729, + b: 0, + c: 0, + pc: 0, + } + }; + assert_eq!(cpu, expected_cpu); + } + + #[test] + fn test_run_program() { + let input = String::from("\ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 +" + ); + let mut cpu = parse_input(input.lines()); + cpu.run(); + assert_eq!(cpu.output, [4,6,3,5,6,3,5,2,1,0]); + + let input = String::from("\ +Register A: 0 +Register B: 0 +Register C: 9 + +Program: 2,6 +" + ); + let mut cpu = parse_input(input.lines()); + cpu.run(); + assert_eq!(cpu.registers.b, 1); + + let input = String::from("\ +Register A: 10 +Register B: 0 +Register C: 0 + +Program: 5,0,5,1,5,4 +" + ); + let mut cpu = parse_input(input.lines()); + cpu.run(); + assert_eq!(cpu.output, [0,1,2]); + + let input = String::from("\ +Register A: 2024 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 +" + ); + let mut cpu = parse_input(input.lines()); + cpu.run(); + assert_eq!(cpu.output, [4,2,5,6,7,7,7,7,3,1,0]); + assert_eq!(cpu.registers.a, 0); + + let input = String::from("\ +Register A: 0 +Register B: 29 +Register C: 9 + +Program: 1,7 +" + ); + let mut cpu = parse_input(input.lines()); + cpu.run(); + // assert_eq!(cpu.registers.b, 27); + + let input = String::from("\ +Register A: 0 +Register B: 2024 +Register C: 43690 + +Program: 4,0 +" + ); + let mut cpu = parse_input(input.lines()); + cpu.run(); + assert_eq!(cpu.registers.b, 44354); + } + + #[test] + fn test_fix_corrupted_program() { + let input = String::from("\ +Register A: 2024 +Register B: 0 +Register C: 0 + +Program: 0,3,5,4,3,0 +" + ); + let cpu = parse_input(input.lines()); + let result = fix_corrupted_program(&cpu); + assert_eq!(result, 117440); + } +}