diff --git a/src/day5.rs b/src/day5.rs new file mode 100644 index 0000000..aafbb03 --- /dev/null +++ b/src/day5.rs @@ -0,0 +1,243 @@ +use std; +use std::convert::TryInto; + +fn get_modes(x: i32) -> (i32, i32, i32, i32) { + ( + x as i32 % 100, + (x as i32 / 100) % 10, + (x as i32 / 1000) % 10, + x as i32 / 10000, + ) +} + +fn get_param(input: Vec, mode: i32, idx: usize) -> i32 { + match mode { + 0 => { + let new_idx: usize = input[idx as usize].try_into().unwrap(); + input[new_idx] + } + 1 => input[idx], + _ => panic!("invalid input"), + } +} + +fn set_param(input: &mut Vec, mode: i32, idx: i32, value: i32) -> () { + match mode { + 0 => { + let new_idx: usize = input[idx as usize].try_into().unwrap(); + input[new_idx] = value; + } + _ => { + panic!("invalid mode for output"); + } + } +} + +fn compute_intcode_extended(p: &mut Vec, input: i32) -> (Vec, Vec) { + let mut idx = 0; + let mut output: Vec = Vec::new(); + + while idx < p.len() - 1 { + let (opcode, m1, m2, m3) = get_modes(p[idx]); + match opcode { + 1 => { + let left = get_param(p.to_vec(), m1, idx + 1); + let right = get_param(p.to_vec(), m2, idx + 2); + let res = left + right; + set_param(p, m3, idx as i32 + 3, res); + idx += 4; + } + 2 => { + let left = get_param(p.to_vec(), m1, idx + 1); + let right = get_param(p.to_vec(), m2, idx + 2); + let res = left * right; + set_param(p, m3, idx as i32 + 3, res); + idx += 4; + } + 3 => { + let new_idx: usize = p[idx as usize + 1].try_into().unwrap(); + p[new_idx] = input; + idx += 2; + } + 4 => { + let value = get_param(p.to_vec(), m1, idx + 1); + output.push(value); + idx += 2; + } + 5 => { + let left = get_param(p.to_vec(), m1, idx + 1); + let right = get_param(p.to_vec(), m2, idx + 2); + if left != 0 { + idx = right as usize; + } else { + idx += 3; + } + } + 6 => { + let left = get_param(p.to_vec(), m1, idx + 1); + let right = get_param(p.to_vec(), m2, idx + 2); + if left == 0 { + idx = right as usize; + } else { + idx += 3; + } + } + 7 => { + let left = get_param(p.to_vec(), m1, idx + 1); + let right = get_param(p.to_vec(), m2, idx + 2); + set_param(p, m3, idx as i32 + 3, (left < right) as i32); + idx += 4; + } + 8 => { + let left = get_param(p.to_vec(), m1, idx + 1); + let right = get_param(p.to_vec(), m2, idx + 2); + set_param(p, m3, idx as i32 + 3, (left == right) as i32); + idx += 4; + } + 99 => { + break; + } + _ => panic!("invalid opcode: {}", opcode), + } + } + (p.to_vec(), output.to_vec()) +} + +pub fn main() -> std::io::Result<()> { + let input: Vec = std::include_str!("../day5-input.txt") + .trim() + .split(",") + .map(|x| x.parse().ok().expect(&format!("{} not a number", x))) + .collect(); + + let (_, output) = compute_intcode_extended(&mut input.clone(), 1); + println!("part 1 = {}", output.last().unwrap()); + + let (_, output) = compute_intcode_extended(&mut input.clone(), 5); + println!("part 2 = {}", output[0]); + Ok(()) +} + +#[test] +fn test_halt() { + let (result, _) = compute_intcode_extended(&mut vec![99], 1); + assert_eq!(result, vec![99]); +} + +#[test] +fn test_write_to_memory() { + let (result, _) = compute_intcode_extended(&mut vec![3, 3, 99, 0], 20); + assert_eq!(20, result[3]); +} + +#[test] +fn test_write_to_output() { + let (_, output) = compute_intcode_extended(&mut vec![4, 2, 99], 1); + assert_eq!(99, output[0]); +} + +#[test] +fn test_add() { + let (result, _) = compute_intcode_extended(&mut vec![1, 2, 2, 0, 99], 1); + assert_eq!(4, result[0]); +} + +#[test] +fn test_mul() { + let (result, _) = compute_intcode_extended(&mut vec![2, 2, 4, 0, 99], 1); + assert_eq!(396, result[0]); +} + +#[test] +fn test_immediate_mode() { + let (result, output) = compute_intcode_extended(&mut vec![1102, 2, 4, 0, 99], 1); + assert_eq!(8, result[0]); +} + +#[test] +fn test_position_mode_equal() { + let (result, output) = + compute_intcode_extended(&mut vec![3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8], 8); + assert_eq!(1, output[0]); +} + +#[test] +fn test_position_mode_not_equal() { + let (result, output) = + compute_intcode_extended(&mut vec![3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8], 10); + assert_eq!(0, output[0]); +} + +#[test] +fn test_position_mode_less_than() { + let (result, output) = + compute_intcode_extended(&mut vec![3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8], 3); + assert_eq!(1, output[0]); +} + +#[test] +fn test_position_mode_greater_than() { + let (result, output) = + compute_intcode_extended(&mut vec![3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8], 10); + assert_eq!(0, output[0]); +} + +#[test] +fn test_immediate_mode_equal() { + let (result, output) = compute_intcode_extended(&mut vec![3, 3, 1108, -1, 8, 3, 4, 3, 99], 8); + assert_eq!(1, output[0]); +} + +#[test] +fn test_immediate_mode_not_equal() { + let (result, output) = compute_intcode_extended(&mut vec![3, 3, 1108, -1, 8, 3, 4, 3, 99], 10); + assert_eq!(0, output[0]); +} + +#[test] +fn test_immediate_mode_less_than() { + let (result, output) = compute_intcode_extended(&mut vec![3, 3, 1107, -1, 8, 3, 4, 3, 99], 3); + assert_eq!(1, output[0]); +} + +#[test] +fn test_immediate_mode_greater_than() { + let (result, output) = compute_intcode_extended(&mut vec![3, 3, 1107, -1, 8, 3, 4, 3, 99], 10); + assert_eq!(0, output[0]); +} + +#[test] +fn test_position_jump_zero() { + let (result, output) = compute_intcode_extended( + &mut vec![3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9], + 0, + ); + assert_eq!(0, output[0]); +} + +#[test] +fn test_position_jump_one() { + let (result, output) = compute_intcode_extended( + &mut vec![3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9], + 100, + ); + assert_eq!(1, output[0]); +} + +#[test] +fn test_immediate_jump_zero() { + let (result, output) = compute_intcode_extended( + &mut vec![3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1], + 0, + ); + assert_eq!(0, output[0]); +} + +#[test] +fn test_immediate_jump_one() { + let (result, output) = compute_intcode_extended( + &mut vec![3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1], + 100, + ); + assert_eq!(1, output[0]); +}