fn parse(input: &str) -> (u64, u64, u64, Vec) { let lines: Vec> = input .lines() .map(|l| l.split_whitespace().collect()) .collect(); ( lines[0].last().unwrap().parse().unwrap(), lines[1].last().unwrap().parse().unwrap(), lines[2].last().unwrap().parse().unwrap(), lines .last() .unwrap() .last() .unwrap() .split(',') .map(|i| i.parse().unwrap()) .collect(), ) } fn combo(a: u64, b: u64, c: u64, op: u64) -> u64 { match op { 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => a, 5 => b, 6 => c, _ => unreachable!(), } } fn solve_1(input: &str) -> String { let (a, b, c, ops) = parse(input); stringify(solve(a, b, c, ops)) } fn solve(mut a: u64, mut b: u64, mut c: u64, ops: Vec) -> Vec { let mut ip = 0; let mut out: Vec = vec![]; while ip < ops.len() { let ins = *ops.get(ip).unwrap(); let op = *ops.get(ip + 1).unwrap(); match ins { 0 => { // adv let result = a >> combo(a, b, c, op); a = result; ip += 2; } 1 => { // bxl let result = b ^ op; b = result; ip += 2; } 2 => { // bst let result = combo(a, b, c, op) % 8; b = result; ip += 2; } 3 => { // jnz if a != 0 { ip = op as usize; } else { ip += 2; } } 4 => { // bxc let result = b ^ c; b = result; ip += 2; } 5 => { // out out.push(combo(a, b, c, op) % 8); ip += 2; } 6 => { // bdv let result = a >> combo(a, b, c, op); b = result; ip += 2; } 7 => { // cdv let result = a >> combo(a, b, c, op); c = result; ip += 2; } _ => unreachable!(), } } out } fn stringify(ops: Vec) -> String { let out = ops .into_iter() .fold("".to_string(), |result, n| result + "," + &n.to_string()); out.as_str()[1..].to_string() } // Decompilation of my program yields the following // 2,4,1,7,7,5,0,3,4,4,1,7,5,5,3,0 // // while a: // b = a % 8 // b = b ^ 7 // c = a >> b // a = a >> 3 // b = b ^ c // b = b ^ 7 // out(b % 8) fn solve_2(input: &str) -> u64 { fn find(ops: &[u64], ans: u64) -> Option { if ops.is_empty() { return Some(ans); } for t in 0..8 { let a = ans << 3 | t; let mut b = a % 8; b = b ^ 7; let c = a >> b; b = b ^ c; b = b ^ 7; let output = b % 8; if output == *ops.last().unwrap() { let sub = find(&ops[..ops.len() - 1], a); if sub.is_some() { return sub; } } } return None; } let (_a, _b, _c, ops) = parse(input); find(&ops[..], 0).unwrap() } fn main() { println!("Hello, this is Patrick!"); let input = include_str!("../input.txt"); let result_1 = solve_1(input); println!("The final output of the program is {}", result_1); let result_2 = solve_2(input); println!( "The lowest positive initial value for register A to get a copy of the program is {}", result_2 ); } #[cfg(test)] mod tests { use super::*; #[test] fn test_1() { let test_input = include_str!("../test.txt"); assert_eq!(solve_1(test_input), "4,6,3,5,6,3,5,2,1,0"); } }