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
use crate::assembunny::Interpreter;
use std::collections::HashSet;
use std::ops::ControlFlow;
use utils::prelude::*;
/// Finding patterns in interpreted assembunny assembly output.
///
/// ```text
/// cpy $N $r3
/// jnz $r2 2
/// jnz 1 6
/// dec $r2
/// dec $r3
/// jnz $r3 -4
/// inc $r1
/// jnz 1 -7
/// ```
/// can be replaced with `$r1 += $r2 / $N`, followed by `$r3 = $N - ($r2 % $N)` and `$r2 = 0`.
/// This reduces the number of simulated cycles for ~300 times when using the previously implemented
/// addition optimization, and ~400 times compared to a naive implementation.
///
/// See also [2016 day 12](crate::Day12) and [2016 day 23](crate::Day23).
#[derive(Clone, Debug)]
pub struct Day25 {
interpreter: Interpreter<false, true>,
}
impl Day25 {
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
Ok(Self {
interpreter: Interpreter::new(input)?,
})
}
#[must_use]
pub fn part1(&self) -> i32 {
let mut seen = HashSet::new();
for i in 1..=i32::MAX {
let mut last = 1;
let mut found_solution = false;
seen.clear();
self.interpreter.execute([i, 0, 0, 0], |v, state| {
if (last == 1 && v != 0) || (last == 0 && v != 1) {
return ControlFlow::Break(());
}
last = v;
if seen.insert((v, state)) {
ControlFlow::Continue(())
} else {
// Looped to previously seen state that produces the correct pattern
found_solution = true;
ControlFlow::Break(())
}
});
if found_solution {
return i;
}
}
panic!("no solution found")
}
#[must_use]
pub fn part2(&self) -> &'static str {
"🎄"
}
}
examples!(Day25 -> (i32, &'static str) []);