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