This commit is contained in:
Stefan Schwarz 2020-04-19 23:02:38 +02:00
parent 0cd663ae2a
commit dadd414faa

View file

@ -4,295 +4,298 @@ use std::io::{self, BufRead, BufReader, Write};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
enum Mode { enum Mode {
Position, Position,
Immediate, Immediate,
} }
impl Default for Mode { impl Default for Mode {
fn default() -> Self { fn default() -> Self {
Mode::Position Mode::Position
} }
} }
impl From<bool> for Mode { impl From<bool> for Mode {
fn from(b: bool) -> Self { fn from(b: bool) -> Self {
match b { match b {
false => Mode::Position, false => Mode::Position,
true => Mode::Immediate, true => Mode::Immediate,
} }
} }
} }
#[derive(Copy, Clone, Default, Debug)] #[derive(Copy, Clone, Default, Debug)]
struct Modes { struct Modes {
a: Mode, a: Mode,
b: Mode, b: Mode,
c: Mode, c: Mode,
} }
impl From<(Mode, Mode, Mode)> for Modes { impl From<(Mode, Mode, Mode)> for Modes {
fn from(modes: (Mode, Mode, Mode)) -> Self { fn from(modes: (Mode, Mode, Mode)) -> Self {
Modes { Modes {
a: modes.0, a: modes.0,
b: modes.1, b: modes.1,
c: modes.2, c: modes.2,
} }
} }
} }
impl From<&ModedOpcode> for Modes { impl From<&ModedOpcode> for Modes {
fn from(mo: &ModedOpcode) -> Self { fn from(mo: &ModedOpcode) -> Self {
mo.modes mo.modes
} }
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum Opcode { enum Opcode {
Add, Add,
Multiply, Multiply,
Input, Input,
Output, Output,
JumpIfTrue, JumpIfTrue,
JumpIfFalse, JumpIfFalse,
LessThan, LessThan,
Equals, Equals,
Halt, Halt,
} }
impl From<&ModedOpcode> for Opcode { impl From<&ModedOpcode> for Opcode {
fn from(mo: &ModedOpcode) -> Self { fn from(mo: &ModedOpcode) -> Self {
mo.op mo.op
} }
} }
impl From<i64> for Opcode { impl From<i64> for Opcode {
fn from(i: i64) -> Self { fn from(i: i64) -> Self {
match i { match i {
1 => Opcode::Add, 1 => Opcode::Add,
2 => Opcode::Multiply, 2 => Opcode::Multiply,
3 => Opcode::Input, 3 => Opcode::Input,
4 => Opcode::Output, 4 => Opcode::Output,
5 => Opcode::JumpIfTrue, 5 => Opcode::JumpIfTrue,
6 => Opcode::JumpIfFalse, 6 => Opcode::JumpIfFalse,
7 => Opcode::LessThan, 7 => Opcode::LessThan,
8 => Opcode::Equals, 8 => Opcode::Equals,
99 => Opcode::Halt, 99 => Opcode::Halt,
_ => panic!("invalid opcode {}", i), _ => panic!("invalid opcode {}", i),
} }
} }
} }
struct ModedOpcode { struct ModedOpcode {
modes: Modes, modes: Modes,
op: Opcode, op: Opcode,
} }
impl From<i64> for ModedOpcode { impl From<i64> for ModedOpcode {
fn from(i: i64) -> Self { fn from(i: i64) -> Self {
let code = i % 100; let code = i % 100;
let a = i % 1000 >= 100; let a = i % 1000 >= 100;
let b = i % 10000 >= 1000; let b = i % 10000 >= 1000;
let c = i > 10000; let c = i > 10000;
let modes = (Mode::from(a), Mode::from(b), Mode::from(c)).into(); let modes = (Mode::from(a), Mode::from(b), Mode::from(c)).into();
ModedOpcode { ModedOpcode {
modes: modes, modes: modes,
op: Opcode::from(code), op: Opcode::from(code),
} }
} }
} }
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
println!("Hello, i am {}.", env::args().next().unwrap()); println!("Hello, i am {}.", env::args().next().unwrap());
let filename = env::args().nth(1).expect("provide file as first param"); let filename = env::args().nth(1).expect("provide file as first param");
let computer = Computer::from(File::open(filename)?); let computer = Computer::from(File::open(filename)?);
computer.clone().run(); computer.clone().run();
Ok(()) Ok(())
} }
struct Computer { struct Computer {
pos: usize, pos: usize,
program: Vec<i64>, program: Vec<i64>,
modes: Modes, modes: Modes,
} }
impl Clone for Computer { impl Clone for Computer {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Computer { Computer {
pos: 0, pos: 0,
program: self.program.clone(), program: self.program.clone(),
modes: Default::default(), modes: Default::default(),
} }
} }
} }
impl From<File> for Computer { impl From<File> for Computer {
fn from(f: File) -> Self { fn from(f: File) -> Self {
let f = BufReader::new(f); let f = BufReader::new(f);
let program: Vec<i64> = f let program: Vec<i64> = f
.split(b',') .split(b',')
.map(|o| { .map(|o| {
let o = o.unwrap(); let o = o.unwrap();
let mut o = o.iter().peekable(); let mut o = o.iter().peekable();
let sign = if o.peek() == Some(&&b'-') { -1 } else { 1 }; let sign = if o.peek() == Some(&&b'-') { -1 } else { 1 };
o.filter(|i| **i >= b'0' && **i <= b'9') o.filter(|i| **i >= b'0' && **i <= b'9')
.fold(0, |s, i| ((i - b'0') as i64 + 10 * s)) .fold(0, |s, i| ((i - b'0') as i64 + 10 * s))
* sign * sign
}) })
.collect(); .collect();
program.into() program.into()
} }
} }
impl From<Vec<i64>> for Computer { impl From<Vec<i64>> for Computer {
fn from(program: Vec<i64>) -> Self { fn from(program: Vec<i64>) -> Self {
Computer { Computer {
pos: 0, pos: 0,
program: program, program: program,
modes: Default::default(), modes: Default::default(),
} }
} }
} }
impl Computer { impl Computer {
fn update(&mut self, u: Vec<(usize, i64)>) -> Computer { fn update(&mut self, u: Vec<(usize, i64)>) -> Computer {
let mut computer = self.clone(); let mut computer = self.clone();
for (pos, val) in u { for (pos, val) in u {
computer.program[pos] = val; computer.program[pos] = val;
} }
computer computer
} }
fn run(&mut self) -> i64 { fn run(&mut self) -> i64 {
loop { loop {
let instruction = self.program[self.pos]; let instruction = self.program[self.pos];
let instruction = ModedOpcode::from(instruction); let instruction = ModedOpcode::from(instruction);
self.modes = (&instruction).into(); self.modes = (&instruction).into();
let advance = match (&instruction).into() { let advance = match (&instruction).into() {
Opcode::Add => self.add(), Opcode::Add => self.add(),
Opcode::Multiply => self.multiply(), Opcode::Multiply => self.multiply(),
Opcode::Input => self.input(), Opcode::Input => self.input(),
Opcode::Output => self.output(), Opcode::Output => self.output(),
Opcode::JumpIfTrue => self.jump_if_true(), Opcode::JumpIfTrue => self.jump_if_true(),
Opcode::JumpIfFalse => self.jump_if_false(), Opcode::JumpIfFalse => self.jump_if_false(),
Opcode::LessThan => self.less_than(), Opcode::LessThan => self.less_than(),
Opcode::Equals => self.equals(), Opcode::Equals => self.equals(),
Opcode::Halt => return self.program[0], Opcode::Halt => return self.program[0],
}; };
self.pos += advance; self.pos += advance;
} }
} }
fn get_a(&self) -> i64 { fn get_a(&self) -> i64 {
let a = self.program[self.pos + 1]; let a = self.program[self.pos + 1];
match self.modes.a { match self.modes.a {
Mode::Position => self.program[a as usize], Mode::Position => self.program[a as usize],
Mode::Immediate => a, Mode::Immediate => a,
} }
} }
fn set_a(&mut self, value: i64) { fn set_a(&mut self, value: i64) {
let a = self.program[self.pos + 1]; let a = self.program[self.pos + 1];
match self.modes.a { match self.modes.a {
Mode::Position => self.program[a as usize] = value, Mode::Position => self.program[a as usize] = value,
Mode::Immediate => self.program[self.pos] = value, Mode::Immediate => self.program[self.pos] = value,
} }
} }
fn get_b(&self) -> i64 { fn get_b(&self) -> i64 {
let b = self.program[self.pos + 2]; let b = self.program[self.pos + 2];
match self.modes.b { match self.modes.b {
Mode::Position => self.program[b as usize], Mode::Position => self.program[b as usize],
Mode::Immediate => b, Mode::Immediate => b,
} }
} }
fn set_c(&mut self, value: i64) { fn set_c(&mut self, value: i64) {
let c = self.program[self.pos + 3]; let c = self.program[self.pos + 3];
match self.modes.c { match self.modes.c {
Mode::Position => self.program[c as usize] = value, Mode::Position => self.program[c as usize] = value,
Mode::Immediate => self.program[self.pos] = value, Mode::Immediate => self.program[self.pos] = value,
} }
} }
fn add(&mut self) -> usize { fn add(&mut self) -> usize {
self.set_c(self.get_a() + self.get_b()); self.set_c(self.get_a() + self.get_b());
4 4
} }
fn multiply(&mut self) -> usize { fn multiply(&mut self) -> usize {
self.set_c(self.get_a() * self.get_b()); self.set_c(self.get_a() * self.get_b());
4 4
} }
fn input(&mut self) -> usize { fn input(&mut self) -> usize {
let mut line = String::new(); let mut line = String::new();
print!("input: "); print!("input: ");
io::stdout().flush().expect("unable to flush output"); io::stdout().flush().expect("unable to flush output");
io::stdin().lock().read_line(&mut line).expect("input failed"); io::stdin()
let value = line.trim().parse().expect("numeric input required"); .lock()
self.set_a(value); .read_line(&mut line)
2 .expect("input failed");
} let value = line.trim().parse().expect("numeric input required");
self.set_a(value);
2
}
fn output(&mut self) -> usize { fn output(&mut self) -> usize {
println!("output: {}", self.get_a()); println!("output: {}", self.get_a());
2 2
} }
fn jump_if_true(&mut self) -> usize { fn jump_if_true(&mut self) -> usize {
if self.get_a() > 0 { if self.get_a() > 0 {
self.pos = self.get_b() as usize; self.pos = self.get_b() as usize;
return 0; return 0;
} }
3 3
} }
fn jump_if_false(&mut self) -> usize { fn jump_if_false(&mut self) -> usize {
if self.get_a() == 0 { if self.get_a() == 0 {
self.pos = self.get_b() as usize; self.pos = self.get_b() as usize;
return 0; return 0;
} }
3 3
} }
fn less_than(&mut self) -> usize { fn less_than(&mut self) -> usize {
if self.get_a() < self.get_b() { if self.get_a() < self.get_b() {
self.set_c(1) self.set_c(1)
} else { } else {
self.set_c(0) self.set_c(0)
} }
4 4
} }
fn equals(&mut self) -> usize { fn equals(&mut self) -> usize {
if self.get_a() == self.get_b() { if self.get_a() == self.get_b() {
self.set_c(1) self.set_c(1)
} else { } else {
self.set_c(0) self.set_c(0)
} }
4 4
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn example1() { fn example1() {
let program: Vec<i64> = vec![1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50]; let program: Vec<i64> = vec![1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50];
assert_eq!(Computer::from(program).run(), 3500) assert_eq!(Computer::from(program).run(), 3500)
} }
#[test] #[test]
fn example2() { fn example2() {
let program: Vec<i64> = vec![1, 0, 0, 0, 99]; let program: Vec<i64> = vec![1, 0, 0, 0, 99];
assert_eq!(Computer::from(program).run(), 2) assert_eq!(Computer::from(program).run(), 2)
} }
#[test] #[test]
fn example3() { fn example3() {
let program: Vec<i64> = vec![1, 1, 1, 4, 99, 5, 6, 0, 99]; let program: Vec<i64> = vec![1, 1, 1, 4, 99, 5, 6, 0, 99];
assert_eq!(Computer::from(program).run(), 30) assert_eq!(Computer::from(program).run(), 30)
} }
} }