year2015/
day23.rs

1use utils::prelude::*;
2
3/// Interpreting assembly.
4#[derive(Clone, Debug)]
5pub struct Day23 {
6    instructions: Vec<Instruction>,
7}
8
9#[derive(Copy, Clone, PartialEq, Eq, Debug)]
10enum Register {
11    A,
12    B,
13}
14
15#[derive(Copy, Clone, PartialEq, Eq, Debug)]
16enum Instruction {
17    Half(Register),
18    Triple(Register),
19    Increment(Register),
20    Jump(i16),
21    JumpIfEven(Register, i16),
22    JumpIfOne(Register, i16),
23}
24
25impl Day23 {
26    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
27        let register = parser::literal_map!(
28            "a" => Register::A,
29            "b" => Register::B,
30        );
31
32        Ok(Self {
33            instructions: parser::parse_tree!(
34                ("hlf ", r @ register) => Instruction::Half(r),
35                ("tpl ", r @ register) => Instruction::Triple(r),
36                ("inc ", r @ register) => Instruction::Increment(r),
37                ("jmp ", v @ parser::i16()) => Instruction::Jump(v),
38                ("jie ", r @ register, ", ", o @ parser::i16()) => Instruction::JumpIfEven(r, o),
39                ("jio ", r @ register, ", ", o @ parser::i16()) => Instruction::JumpIfOne(r, o),
40            )
41            .parse_lines(input)?,
42        })
43    }
44
45    #[must_use]
46    pub fn part1(&self) -> u64 {
47        self.execute(0, 0)
48    }
49
50    #[must_use]
51    pub fn part2(&self) -> u64 {
52        self.execute(1, 0)
53    }
54
55    fn execute(&self, mut a: u64, mut b: u64) -> u64 {
56        let mut pc = 0;
57
58        while let Some(&instruction) = pc
59            .try_into()
60            .ok()
61            .and_then(|i: usize| self.instructions.get(i))
62        {
63            pc += 1;
64            match instruction {
65                Instruction::Half(Register::A) => a /= 2,
66                Instruction::Half(Register::B) => b /= 2,
67                Instruction::Triple(Register::A) => a *= 3,
68                Instruction::Triple(Register::B) => b *= 3,
69                Instruction::Increment(Register::A) => a += 1,
70                Instruction::Increment(Register::B) => b += 1,
71                Instruction::Jump(offset) => pc += offset - 1,
72                Instruction::JumpIfEven(Register::A, offset) if a % 2 == 0 => pc += offset - 1,
73                Instruction::JumpIfEven(Register::B, offset) if b % 2 == 0 => pc += offset - 1,
74                Instruction::JumpIfOne(Register::A, offset) if a == 1 => pc += offset - 1,
75                Instruction::JumpIfOne(Register::B, offset) if b == 1 => pc += offset - 1,
76                Instruction::JumpIfEven(_, _) | Instruction::JumpIfOne(_, _) => {}
77            }
78        }
79
80        b
81    }
82}
83
84examples!(Day23 -> (u64, u64) []);