1use std::collections::VecDeque;
3
4const EXTRA: usize = 6_000;
8
9pub enum State {
10 Input,
11 Output(i64),
12 Halted,
13}
14
15pub struct Computer {
16 pc: usize,
17 base: usize,
18 code: Vec<usize>,
19 input: VecDeque<usize>,
20}
21
22impl Computer {
23 #[must_use]
24 pub fn new(input: &[i64]) -> Self {
25 let mut code = Vec::with_capacity(input.len() + EXTRA);
26 code.extend(input.iter().map(|&i| i as usize));
27 code.resize(code.len() + EXTRA, 0);
28
29 Self { pc: 0, base: 0, code, input: VecDeque::new() }
30 }
31
32 pub fn input(&mut self, value: i64) {
33 self.input.push_back(value as usize);
34 }
35
36 pub fn input_ascii(&mut self, ascii: &str) {
37 self.input.extend(ascii.bytes().map(usize::from));
38 }
39
40 pub fn reset(&mut self) {
42 self.pc = 0;
43 self.base = 0;
44 self.input.clear();
45 }
46
47 #[must_use]
50 pub fn run(&mut self) -> State {
51 loop {
52 let op = self.code[self.pc];
53
54 match op % 100 {
55 1 => {
57 let first = self.address(op / 100, 1);
58 let second = self.address(op / 1000, 2);
59 let third = self.address(op / 10000, 3);
60 self.code[third] = self.code[first].wrapping_add(self.code[second]);
61 self.pc += 4;
62 }
63 2 => {
65 let first = self.address(op / 100, 1);
66 let second = self.address(op / 1000, 2);
67 let third = self.address(op / 10000, 3);
68 self.code[third] = self.code[first].wrapping_mul(self.code[second]);
69 self.pc += 4;
70 }
71 3 => {
73 let Some(value) = self.input.pop_front() else {
74 break State::Input;
75 };
76 let first = self.address(op / 100, 1);
77 self.code[first] = value;
78 self.pc += 2;
79 }
80 4 => {
82 let first = self.address(op / 100, 1);
83 let value = self.code[first];
84 self.pc += 2;
85 break State::Output(value as i64);
86 }
87 5 => {
89 let first = self.address(op / 100, 1);
90 let second = self.address(op / 1000, 2);
91 let zero = self.code[first] == 0;
92 self.pc = if zero { self.pc + 3 } else { self.code[second] };
93 }
94 6 => {
96 let first = self.address(op / 100, 1);
97 let second = self.address(op / 1000, 2);
98 let zero = self.code[first] == 0;
99 self.pc = if zero { self.code[second] } else { self.pc + 3 };
100 }
101 7 => {
103 let first = self.address(op / 100, 1);
104 let second = self.address(op / 1000, 2);
105 let third = self.address(op / 10000, 3);
106 let value = (self.code[first] as i64) < (self.code[second] as i64);
107 self.code[third] = value as usize;
108 self.pc += 4;
109 }
110 8 => {
112 let first = self.address(op / 100, 1);
113 let second = self.address(op / 1000, 2);
114 let third = self.address(op / 10000, 3);
115 let value = self.code[first] == self.code[second];
116 self.code[third] = value as usize;
117 self.pc += 4;
118 }
119 9 => {
121 let first = self.address(op / 100, 1);
122 self.base = self.base.wrapping_add(self.code[first]);
123 self.pc += 2;
124 }
125 _ => break State::Halted,
126 }
127 }
128 }
129
130 #[inline]
132 fn address(&self, mode: usize, offset: usize) -> usize {
133 let index = self.pc + offset;
134 match mode % 10 {
135 0 => self.code[index],
136 1 => index,
137 2 => self.base.wrapping_add(self.code[index]),
138 _ => unreachable!(),
139 }
140 }
141}