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
use super::assembly::{Instruction, Program, Value};
use crate::input::Input;
fn is_prime(number: i32) -> bool {
let number_sqrt = f64::from(number).sqrt() as i32;
(2..=number_sqrt).all(|i| number % i != 0)
}
pub fn solve(input: &mut Input) -> Result<u32, String> {
let mut program = Program::parse(input.text)?;
if input.is_part_one() {
program.run_until_recover(None);
Ok(program.mul_count)
} else {
// Register a is set to 1 at start.
//
// 0: set b 67 b = 67
// 1: set c b c = b
// 2: jnz a 2 if a == 0: // True in part 1, false in part 2.
// 3: jnz 1 5 GOTO 5+
// 4: mul b 100 b *= 100 // b = 6700
// 5: sub b -100000 b += 100000 // b = 106700
// 6: set c b c = b // c = 106700
// 7: sub c -17000 c += 17000 // c = 123700
//
// Initialization done, now entering main loop with (b = 106700, c = 123700):
//
// b = 106700
// c = 123700
// 8: set f 1 while (true) { f = 1
// 9: set d 2 d = 2
// 10: set e 2 outer_loop: { e = 2
// 11: set g d inner_loop: { // g = d
// 12: mul g e // g *= e
// 13: sub g b // g -= b
// 14: jnz g 2 if b == d * e:
// 15: set f 0 f = 0
// 16: sub e -1 e += 1
// 17: set g e // g = e
// 18: sub g b // g -= b
// 19: jnz g -8 if b != e: continue inner_loop
// 20: sub d -1 d += 1
// 21: set g d // g = d - b
// 22: sub g b // g -= b
// 23: jnz g -13 if b != d: continue outer_loop
// 24: jnz f 2 if f == 0:
// 25: sub h -1 h += 1
// 26: set g b // g = b - 123700
// 27: sub g c // g -= c
// 28: jnz g 2 if b == 123700:
// 29: jnz 1 3 exit()
// 30: sub b -17 b += 17
// 31: jnz 1 -23 }}}
//
// Rewritten, with f renamed to false and considered a boolean, h renamed to count:
//
// count = 0
// for b in 106700..=123700, step by 17:
// found = false
// for d in 2..b:
// for e in 2..b:
// if b == d * e: found = true
// if found: count += 1
// return count
//
// So the program is counting the number of non-prime values of b.
let start_value = {
match program.instructions[0] {
Instruction::Set(_, Value::Number(number)) => 100 * (number as i32) + 100_000,
_ => {
return Err("Unsupported program".to_string());
}
}
};
let end_value = start_value + 17_000;
Ok((start_value..=end_value)
.step_by(17)
.filter(|&n| !is_prime(n))
.count() as u32)
}
}
#[test]
pub fn tests() {
use crate::input::{test_part_one, test_part_two};
let real_input = include_str!("day23_input.txt");
test_part_one!(real_input => 4225);
test_part_two!(real_input => 905);
}