1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
use crate::Input; #[derive(Copy, Clone, Debug)] enum Instruction { Half(u8), Triple(u8), Increment(u8), Jump(i16), JumpIfEven(u8, i16), JumpIfOne(u8, i16), } #[derive(Debug)] struct Computer { registers: [u32; 2], instructions: Vec<Instruction>, } impl Computer { fn parse_register(specifier: &str) -> Result<u8, String> { Ok(match specifier { "a" | "a," => 0, "b" => 1, _ => { return Err("Invalid register (not 'a' or 'b')".to_string()); } }) } fn parse(input: &str) -> Result<Self, String> { let mut instructions = Vec::new(); for line in input.lines() { let parts = line.split(' ').collect::<Vec<_>>(); instructions.push(match parts[0] { "hlf" => Instruction::Half(Self::parse_register(parts[1])?), "tpl" => Instruction::Triple(Self::parse_register(parts[1])?), "inc" => Instruction::Increment(Self::parse_register(parts[1])?), "jmp" => Instruction::Jump( parts[1] .parse::<i16>() .map_err(|_| "Invalid jmp parameter")?, ), "jie" => Instruction::JumpIfEven( Self::parse_register(parts[1])?, parts[2] .parse::<i16>() .map_err(|_| "Invalid jie parameter")?, ), "jio" => Instruction::JumpIfOne( Self::parse_register(parts[1])?, parts[2] .parse::<i16>() .map_err(|_| "Invalid jio parameter")?, ), _ => { return Err("Invalid instruction".to_string()); } }); } Ok(Self { registers: [0, 0], instructions, }) } fn run(&mut self) { let mut instruction_pointer = 0_i16; loop { if instruction_pointer < 0 { break; } match self.instructions.get(instruction_pointer as usize) { Some(&Instruction::Increment(register)) => { self.registers[register as usize] += 1; instruction_pointer += 1; } Some(&Instruction::Half(register)) => { self.registers[register as usize] /= 2; instruction_pointer += 1; } Some(&Instruction::Triple(register)) => { self.registers[register as usize] *= 3; instruction_pointer += 1; } Some(&Instruction::Jump(offset)) => { instruction_pointer += offset; } Some(&Instruction::JumpIfEven(register, offset)) => { instruction_pointer += if self.registers[register as usize] % 2 == 0 { offset } else { 1 } } Some(&Instruction::JumpIfOne(register, offset)) => { instruction_pointer += if self.registers[register as usize] == 1 { offset } else { 1 } } None => { break; } } } } } pub fn solve(input: &mut Input) -> Result<u32, String> { let mut computer = Computer::parse(input.text)?; computer.registers[0] = input.part_values(0, 1); computer.run(); Ok(computer.registers[1]) } #[test] pub fn tests() { use crate::{test_part_one, test_part_two}; let real_input = include_str!("day23_input.txt"); test_part_one!(real_input => 307); test_part_two!(real_input => 160); }