1#[derive(Copy, Clone, PartialEq, Eq)]
2pub struct Registers {
3 pub values: [u64; 6],
4}
5
6#[derive(Copy, Clone)]
7pub struct Instruction {
8 opcode: Opcode,
9 pub a: u64,
10 pub b: u64,
11 pub c: u64,
12}
13
14pub struct Program {
15 pub instruction_pointer_index: u8,
16 pub instructions: Vec<Instruction>,
17 pub registers: Registers,
18}
19
20impl Program {
21 pub fn instruction_pointer(&self) -> Result<u64, String> {
22 self.registers
23 .values
24 .get(self.instruction_pointer_index as usize)
25 .copied()
26 .ok_or_else(|| "Invalid instruction pointer".to_string())
27 }
28
29 pub fn execute_one_instruction(&mut self) -> Result<bool, String> {
30 let ip = self.instruction_pointer()?;
31 if ip as usize >= self.instructions.len() {
32 return Ok(false);
33 }
34 let instruction = self.instructions[ip as usize];
35 self.registers.apply(
36 instruction.opcode,
37 instruction.a,
38 instruction.b,
39 instruction.c,
40 );
41 self.registers.values[self.instruction_pointer_index as usize] += 1;
42 Ok(true)
43 }
44
45 pub fn execute_until_halt(&mut self, max_instructions: u32) -> Result<u64, String> {
46 let mut loop_count = 0;
47 while self.execute_one_instruction()? {
48 loop_count += 1;
49 if loop_count > max_instructions {
50 return Err(format!("Aborting after {max_instructions} instructions"));
51 }
52 }
53 Ok(self.registers.values[0])
54 }
55
56 pub fn parse(input_string: &str) -> Result<Self, String> {
57 let mut lines = input_string.lines();
58 let first_line = lines.next().ok_or("Empty input")?;
59
60 if first_line.len() < 5 {
61 return Err("Invalid first line of elfcode".to_string());
62 }
63 let error = |_| "Invalid elfcode instruction";
64 let instruction_pointer_index = (first_line[4..]).parse::<u8>().map_err(error)?;
65
66 let mut instructions = Vec::new();
67 for line in lines {
68 let parts: Vec<&str> = line.split_whitespace().collect();
69 if parts.len() != 4 {
70 return Err("Invalid elfcode - not four words for instruction".into());
71 }
72 let opcode = opcode_from_str(parts[0])?;
73 let a = parts[1].parse::<u64>().map_err(error)?;
74 let b = parts[2].parse::<u64>().map_err(error)?;
75 let c = parts[3].parse::<u64>().map_err(error)?;
76 instructions.push(Instruction { opcode, a, b, c });
77 }
78
79 Ok(Self {
80 instruction_pointer_index,
81 instructions,
82 registers: Registers::new(),
83 })
84 }
85
86 pub fn optimize(&mut self) {
87 for (line, instruction) in self.instructions.iter_mut().enumerate() {
88 match instruction.opcode {
89 Opcode::Addi => {
90 if instruction.a as u8 == self.instruction_pointer_index {
91 instruction.opcode = Opcode::Seti;
92 instruction.a = line as u64 + instruction.b;
93 instruction.b = 0; }
95 }
96 Opcode::Mulr => {
97 if instruction.a as u8 == self.instruction_pointer_index
98 && instruction.b as u8 == self.instruction_pointer_index
99 {
100 instruction.opcode = Opcode::Seti;
101 instruction.a = line as u64 * line as u64;
102 instruction.b = 0; }
104 }
105 Opcode::Muli => {
106 if instruction.a as u8 == self.instruction_pointer_index {
107 instruction.opcode = Opcode::Seti;
108 instruction.a = line as u64 * instruction.b;
109 instruction.b = 0; }
111 }
112 _ => {}
113 }
114 }
115 }
116}
117
118#[derive(Copy, Clone, Eq, PartialEq, Hash)]
119pub enum Opcode {
120 Addr, Addi, Mulr, Muli, Banr, Bani, Borr, Bori, Setr, Seti, Gtir, Gtri, Gtrr, Eqir, Eqri, Eqrr, }
137
138fn opcode_from_str(name: &str) -> Result<Opcode, String> {
139 Ok(match name {
140 "addr" => Opcode::Addr,
141 "addi" => Opcode::Addi,
142 "mulr" => Opcode::Mulr,
143 "muli" => Opcode::Muli,
144 "banr" => Opcode::Banr,
145 "bani" => Opcode::Bani,
146 "borr" => Opcode::Borr,
147 "bori" => Opcode::Bori,
148 "setr" => Opcode::Setr,
149 "seti" => Opcode::Seti,
150 "gtir" => Opcode::Gtir,
151 "gtri" => Opcode::Gtri,
152 "gtrr" => Opcode::Gtrr,
153 "eqir" => Opcode::Eqir,
154 "eqri" => Opcode::Eqri,
155 "eqrr" => Opcode::Eqrr,
156 _ => {
157 return Err(format!("No matching opcode: {name}"));
158 }
159 })
160}
161
162impl Registers {
163 pub(crate) const fn new() -> Self {
164 Self {
165 values: [0, 0, 0, 0, 0, 0],
166 }
167 }
168
169 const fn reg(&self, index: u64) -> u64 {
170 self.values[index as usize]
171 }
172
173 pub(crate) fn apply(&mut self, opcode: Opcode, a: u64, b: u64, c: u64) {
174 let c = c as usize;
175 self.values[c] = match opcode {
176 Opcode::Addr => self.reg(a) + self.reg(b),
177 Opcode::Addi => self.reg(a) + b,
178 Opcode::Mulr => self.reg(a) * self.reg(b),
179 Opcode::Muli => self.reg(a) * b,
180 Opcode::Banr => self.reg(a) & self.reg(b),
181 Opcode::Bani => self.reg(a) & b,
182 Opcode::Borr => self.reg(a) | self.reg(b),
183 Opcode::Bori => self.reg(a) | b,
184 Opcode::Setr => self.reg(a),
185 Opcode::Seti => a,
186 Opcode::Gtir => u64::from(a > self.reg(b)),
187 Opcode::Gtri => u64::from(self.reg(a) > b),
188 Opcode::Gtrr => u64::from(self.reg(a) > self.reg(b)),
189 Opcode::Eqir => u64::from(a == self.reg(b)),
190 Opcode::Eqri => u64::from(self.reg(a) == b),
191 Opcode::Eqrr => u64::from(self.reg(a) == self.reg(b)),
192 }
193 }
194}