Skip to main content

aoc/year2015/
day23.rs

1//! # Opening the Turing Lock
2//!
3//! Reverse engineering the code shows that it calculates the length of the
4//! [3n + 1 sequence](https://en.wikipedia.org/wiki/Collatz_conjecture)
5//! for one of two different numbers chosen depending on whether `a` is 0 or 1.
6//!
7//! The code is fast enough to emulate directly without needing any understanding of what it's
8//! doing.
9use crate::util::parse::*;
10
11pub enum Op {
12    Hlf,
13    Tpl,
14    IncA,
15    IncB,
16    Jmp(usize),
17    Jie(usize),
18    Jio(usize),
19}
20
21pub fn parse(input: &str) -> Vec<Op> {
22    input
23        .lines()
24        .enumerate()
25        .map(|(i, s)| match s {
26            "hlf a" => Op::Hlf,
27            "tpl a" => Op::Tpl,
28            "inc a" => Op::IncA,
29            "inc b" => Op::IncB,
30            _ => {
31                let index = i.wrapping_add_signed(s.signed());
32                match &s[..3] {
33                    "jmp" => Op::Jmp(index),
34                    "jie" => Op::Jie(index),
35                    "jio" => Op::Jio(index),
36                    _ => unreachable!(),
37                }
38            }
39        })
40        .collect()
41}
42
43pub fn part1(input: &[Op]) -> u64 {
44    execute(input, 0)
45}
46
47pub fn part2(input: &[Op]) -> u64 {
48    execute(input, 1)
49}
50
51fn execute(input: &[Op], mut a: u64) -> u64 {
52    let mut pc = 0;
53    let mut b = 0;
54
55    while pc < input.len() {
56        match input[pc] {
57            Op::Hlf => {
58                a /= 2;
59                pc += 1;
60            }
61            Op::Tpl => {
62                a *= 3;
63                pc += 1;
64            }
65            Op::IncA => {
66                a += 1;
67                pc += 1;
68            }
69            Op::IncB => {
70                b += 1;
71                pc += 1;
72            }
73            Op::Jmp(index) => pc = index,
74            Op::Jie(index) => pc = if a.is_multiple_of(2) { index } else { pc + 1 },
75            Op::Jio(index) => pc = if a == 1 { index } else { pc + 1 },
76        }
77    }
78
79    b
80}