aoc/year2017/day23.rs
1//! # Coprocessor Conflagration
2//!
3//! Just like [`Day 18`] reverse engineering the code is essential. The entire input can be reduced
4//! to only the very first number.
5//!
6//! ```none
7//! set b $NUMBER if a == 0 {
8//! set c b b = $NUMBER;
9//! jnz a 2 c = b;
10//! jnz 1 5 } else {
11//! mul b 100 b = 100000 + 100 * $NUMBER;
12//! sub b -100000 c = b + 17000;
13//! set c b }
14//! sub c -17000
15//! set f 1 for b in (b..=c).step_by(17) {
16//! set d 2 f = 1;
17//! set e 2 for d in 2..b {
18//! set g d for e in 2..b {
19//! mul g e if d * e == b {
20//! sub g b f = 0;
21//! jnz g 2 }
22//! set f 0
23//! sub e -1
24//! set g e
25//! sub g b
26//! jnz g -8 }
27//! sub d -1
28//! set g d
29//! sub g b
30//! jnz g -13 }
31//! jnz f 2
32//! sub h -1 if f == 0 {
33//! set g b h += 1;
34//! sub g c }
35//! jnz g 2
36//! jnz 1 3
37//! sub b -17
38//! jnz 1 -23 }
39//! ```
40//!
41//! ## Part One
42//!
43//! The number of `mul` operations is the product of the two inner loops from 2 to `n` exclusive.
44//!
45//! ## Part Two
46//!
47//! Counts the number of composite numbers starting from `100,000 + 100 * n` checking the next
48//! 1,000 numbers in steps of 17. The raw code take `O(n²)` complexity for each number so emulating
49//! this directly would take at least 10⁵.10⁵.10³ = 10¹³ = 10,000,000,000,000 steps.
50//!
51//! [`Day 18`]: crate::year2017::day18
52use crate::util::parse::*;
53
54/// We only need the vrey first number from the input.
55pub fn parse(input: &str) -> u32 {
56 input.unsigned()
57}
58
59/// The number of `mul` operations is `(n - 2)²`
60pub fn part1(input: &u32) -> u32 {
61 (input - 2) * (input - 2)
62}
63
64/// Count the number of composite numbers in a range calculated from the input number.
65pub fn part2(input: &u32) -> usize {
66 (0..=1000).filter_map(|n| composite(100_000 + 100 * input + 17 * n)).count()
67}
68
69/// Simple [prime number check](https://en.wikipedia.org/wiki/Primality_test)
70/// of all factors from 2 to √n inclusive.
71fn composite(n: u32) -> Option<u32> {
72 for f in 2..=n.isqrt() {
73 if n % f == 0 {
74 return Some(n);
75 }
76 }
77
78 None
79}