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