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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::input::Input;
#[derive(Copy, Clone)]
enum Instruction {
Half(u8),
Triple(u8),
Increment(u8),
Jump(i16),
JumpIfEven(u8, i16),
JumpIfOne(u8, i16),
}
struct Computer {
registers: [u32; 2],
instructions: Vec<Instruction>,
}
impl Computer {
fn parse_register(specifier: &str) -> Result<u8, String> {
Ok(match specifier {
"a" | "a," => 0,
"b" => 1,
_ => {
return Err("Invalid register (not 'a' or 'b')".to_string());
}
})
}
fn parse(input: &str) -> Result<Self, String> {
let mut instructions = Vec::new();
for line in input.lines() {
let parts = line.split(' ').collect::<Vec<_>>();
instructions.push(match parts[0] {
"hlf" => Instruction::Half(Self::parse_register(parts[1])?),
"tpl" => Instruction::Triple(Self::parse_register(parts[1])?),
"inc" => Instruction::Increment(Self::parse_register(parts[1])?),
"jmp" => Instruction::Jump(
parts[1]
.parse::<i16>()
.map_err(|_| "Invalid jmp parameter")?,
),
"jie" => Instruction::JumpIfEven(
Self::parse_register(parts[1])?,
parts[2]
.parse::<i16>()
.map_err(|_| "Invalid jie parameter")?,
),
"jio" => Instruction::JumpIfOne(
Self::parse_register(parts[1])?,
parts[2]
.parse::<i16>()
.map_err(|_| "Invalid jio parameter")?,
),
_ => {
return Err("Invalid instruction".to_string());
}
});
}
Ok(Self {
registers: [0, 0],
instructions,
})
}
fn run(&mut self) {
let mut instruction_pointer = 0_i16;
loop {
if instruction_pointer < 0 {
break;
}
match self.instructions.get(instruction_pointer as usize) {
Some(&Instruction::Increment(register)) => {
self.registers[register as usize] += 1;
instruction_pointer += 1;
}
Some(&Instruction::Half(register)) => {
self.registers[register as usize] /= 2;
instruction_pointer += 1;
}
Some(&Instruction::Triple(register)) => {
self.registers[register as usize] *= 3;
instruction_pointer += 1;
}
Some(&Instruction::Jump(offset)) => {
instruction_pointer += offset;
}
Some(&Instruction::JumpIfEven(register, offset)) => {
instruction_pointer += if self.registers[register as usize] % 2 == 0 {
offset
} else {
1
}
}
Some(&Instruction::JumpIfOne(register, offset)) => {
instruction_pointer += if self.registers[register as usize] == 1 {
offset
} else {
1
}
}
None => {
break;
}
}
}
}
}
pub fn solve(input: &mut Input) -> Result<u32, String> {
let mut computer = Computer::parse(input.text)?;
computer.registers[0] = input.part_values(0, 1);
computer.run();
Ok(computer.registers[1])
}
#[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 => 307);
test_part_two!(real_input => 160);
}