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