|
|
|
@ -0,0 +1,245 @@
|
|
|
|
|
use std::fs::File;
|
|
|
|
|
use std::io::{BufRead, BufReader};
|
|
|
|
|
|
|
|
|
|
type Registers = [usize; 6];
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct Opcode {
|
|
|
|
|
cmd: String,
|
|
|
|
|
args: OpcodeArgs,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type OpcodeArgs = [usize; 3];
|
|
|
|
|
|
|
|
|
|
struct Program {
|
|
|
|
|
registers: Registers,
|
|
|
|
|
instructions: Vec<Opcode>,
|
|
|
|
|
ip: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn iter_to_opcode(iter: &mut std::str::SplitWhitespace) -> Opcode {
|
|
|
|
|
Opcode {
|
|
|
|
|
cmd: iter.nth(0).unwrap().to_string(),
|
|
|
|
|
args: [
|
|
|
|
|
iter.nth(0).unwrap().parse::<usize>().unwrap(),
|
|
|
|
|
iter.nth(0).unwrap().parse::<usize>().unwrap(),
|
|
|
|
|
iter.nth(0).unwrap().parse::<usize>().unwrap(),
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn read_program_from_file(filename: &str) -> Program {
|
|
|
|
|
let mut lines = BufReader::new(File::open(filename).unwrap()).lines();
|
|
|
|
|
let ip = lines.nth(0).unwrap();
|
|
|
|
|
let instructions = lines
|
|
|
|
|
.map(|line| iter_to_opcode(&mut line.unwrap().split_whitespace()))
|
|
|
|
|
.collect();
|
|
|
|
|
Program {
|
|
|
|
|
registers: [0usize; 6],
|
|
|
|
|
instructions,
|
|
|
|
|
ip: ip
|
|
|
|
|
.unwrap()
|
|
|
|
|
.split_whitespace()
|
|
|
|
|
.nth(1)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.parse::<usize>()
|
|
|
|
|
.unwrap(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn addr(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] + input_registers[args[1]];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn addi(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] + args[1];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mulr(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] * input_registers[args[1]];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn muli(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] * args[1];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn banr(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] & input_registers[args[1]];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn bani(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] & args[1];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn borr(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] | input_registers[args[1]];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn bori(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]] | args[1];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn setr(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = input_registers[args[0]];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn seti(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
output_registers[args[2]] = args[0];
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gtir(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
if args[0] > input_registers[args[1]] {
|
|
|
|
|
output_registers[args[2]] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
output_registers[args[2]] = 0;
|
|
|
|
|
}
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gtri(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
if input_registers[args[0]] > args[1] {
|
|
|
|
|
output_registers[args[2]] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
output_registers[args[2]] = 0;
|
|
|
|
|
}
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gtrr(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
if input_registers[args[0]] > input_registers[args[1]] {
|
|
|
|
|
output_registers[args[2]] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
output_registers[args[2]] = 0;
|
|
|
|
|
}
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn eqir(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
if args[0] == input_registers[args[1]] {
|
|
|
|
|
output_registers[args[2]] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
output_registers[args[2]] = 0;
|
|
|
|
|
}
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn eqri(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
if input_registers[args[0]] == args[1] {
|
|
|
|
|
output_registers[args[2]] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
output_registers[args[2]] = 0;
|
|
|
|
|
}
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn eqrr(input_registers: Registers, args: OpcodeArgs) -> Registers {
|
|
|
|
|
let mut output_registers = input_registers.clone();
|
|
|
|
|
if input_registers[args[0]] == input_registers[args[1]] {
|
|
|
|
|
output_registers[args[2]] = 1;
|
|
|
|
|
} else {
|
|
|
|
|
output_registers[args[2]] = 0;
|
|
|
|
|
}
|
|
|
|
|
//dbg!(output_registers);
|
|
|
|
|
output_registers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn execute_program(program: &mut Program) {
|
|
|
|
|
while let Some(op) = program.instructions.get(program.registers[program.ip]) {
|
|
|
|
|
//dbg!(op);
|
|
|
|
|
let output_registers = match op.cmd.as_str() {
|
|
|
|
|
"addr" => addr(program.registers, op.args),
|
|
|
|
|
"addi" => addi(program.registers, op.args),
|
|
|
|
|
"mulr" => mulr(program.registers, op.args),
|
|
|
|
|
"muli" => muli(program.registers, op.args),
|
|
|
|
|
"banr" => banr(program.registers, op.args),
|
|
|
|
|
"bani" => bani(program.registers, op.args),
|
|
|
|
|
"borr" => borr(program.registers, op.args),
|
|
|
|
|
"bori" => bori(program.registers, op.args),
|
|
|
|
|
"setr" => setr(program.registers, op.args),
|
|
|
|
|
"seti" => seti(program.registers, op.args),
|
|
|
|
|
"gtir" => gtir(program.registers, op.args),
|
|
|
|
|
"gtri" => gtri(program.registers, op.args),
|
|
|
|
|
"gtrr" => gtrr(program.registers, op.args),
|
|
|
|
|
"eqir" => eqir(program.registers, op.args),
|
|
|
|
|
"eqri" => eqri(program.registers, op.args),
|
|
|
|
|
"eqrr" => eqrr(program.registers, op.args),
|
|
|
|
|
_ => panic!("No decoded instruction available for {}", op.cmd),
|
|
|
|
|
};
|
|
|
|
|
program.registers[0] = output_registers[0];
|
|
|
|
|
program.registers[1] = output_registers[1];
|
|
|
|
|
program.registers[2] = output_registers[2];
|
|
|
|
|
program.registers[3] = output_registers[3];
|
|
|
|
|
program.registers[4] = output_registers[4];
|
|
|
|
|
program.registers[5] = output_registers[5];
|
|
|
|
|
program.registers[program.ip] += 1;
|
|
|
|
|
}
|
|
|
|
|
program.registers[program.ip] -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
let mut program = read_program_from_file("input");
|
|
|
|
|
execute_program(&mut program);
|
|
|
|
|
println!("final value of register 0: {:?}", program.registers[0]);
|
|
|
|
|
let mut program2 = read_program_from_file("input");
|
|
|
|
|
program2.registers[0] = 1;
|
|
|
|
|
execute_program(&mut program2);
|
|
|
|
|
println!("final value of register 0 with modified start value {}", program2.registers[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_sample_one() {
|
|
|
|
|
let mut program = read_program_from_file("test-input");
|
|
|
|
|
execute_program(&mut program);
|
|
|
|
|
let output_registers = program.registers;
|
|
|
|
|
assert_eq!(output_registers[0], 6);
|
|
|
|
|
assert_eq!(output_registers[1], 5);
|
|
|
|
|
assert_eq!(output_registers[2], 6);
|
|
|
|
|
assert_eq!(output_registers[3], 0);
|
|
|
|
|
assert_eq!(output_registers[4], 0);
|
|
|
|
|
assert_eq!(output_registers[5], 9);
|
|
|
|
|
}
|
|
|
|
|
}
|