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 pub fn new(input: &[i64]) -> Computer {
24 let mut code = Vec::with_capacity(input.len() + EXTRA);
25 code.extend(input.iter().map(|&i| i as usize));
26 code.resize(code.len() + EXTRA, 0);
27
28 Computer { pc: 0, base: 0, code, input: VecDeque::new() }
29 }
30
31 pub fn input(&mut self, value: i64) {
32 self.input.push_back(value as usize);
33 }
34
35 pub fn input_ascii(&mut self, ascii: &str) {
36 self.input.extend(ascii.bytes().map(|b| b as usize));
37 }
38
39 pub fn reset(&mut self) {
41 self.pc = 0;
42 self.base = 0;
43 self.input.clear();
44 }
45
46 pub fn run(&mut self) -> State {
49 loop {
50 let op = self.code[self.pc];
51
52 match op % 100 {
53 1 => {
55 let first = self.address(op / 100, 1);
56 let second = self.address(op / 1000, 2);
57 let third = self.address(op / 10000, 3);
58 self.code[third] = self.code[first].wrapping_add(self.code[second]);
59 self.pc += 4;
60 }
61 2 => {
63 let first = self.address(op / 100, 1);
64 let second = self.address(op / 1000, 2);
65 let third = self.address(op / 10000, 3);
66 self.code[third] = self.code[first].wrapping_mul(self.code[second]);
67 self.pc += 4;
68 }
69 3 => {
71 let Some(value) = self.input.pop_front() else {
72 break State::Input;
73 };
74 let first = self.address(op / 100, 1);
75 self.code[first] = value;
76 self.pc += 2;
77 }
78 4 => {
80 let first = self.address(op / 100, 1);
81 let value = self.code[first];
82 self.pc += 2;
83 break State::Output(value as i64);
84 }
85 5 => {
87 let first = self.address(op / 100, 1);
88 let second = self.address(op / 1000, 2);
89 let value = self.code[first] == 0;
90 self.pc = if value { self.pc + 3 } else { self.code[second] };
91 }
92 6 => {
94 let first = self.address(op / 100, 1);
95 let second = self.address(op / 1000, 2);
96 let value = self.code[first] == 0;
97 self.pc = if value { self.code[second] } else { self.pc + 3 };
98 }
99 7 => {
101 let first = self.address(op / 100, 1);
102 let second = self.address(op / 1000, 2);
103 let third = self.address(op / 10000, 3);
104 let value = (self.code[first] as i64) < (self.code[second] as i64);
105 self.code[third] = value as usize;
106 self.pc += 4;
107 }
108 8 => {
110 let first = self.address(op / 100, 1);
111 let second = self.address(op / 1000, 2);
112 let third = self.address(op / 10000, 3);
113 let value = self.code[first] == self.code[second];
114 self.code[third] = value as usize;
115 self.pc += 4;
116 }
117 9 => {
119 let first = self.address(op / 100, 1);
120 self.base = self.base.wrapping_add(self.code[first]);
121 self.pc += 2;
122 }
123 _ => break State::Halted,
124 }
125 }
126 }
127
128 #[inline]
130 fn address(&self, mode: usize, offset: usize) -> usize {
131 let index = self.pc + offset;
132 match mode % 10 {
133 0 => self.code[index],
134 1 => index,
135 2 => self.base.wrapping_add(self.code[index]),
136 _ => unreachable!(),
137 }
138 }
139}