3 changed files with 255 additions and 0 deletions
@ -0,0 +1 @@ |
|||
3,225,1,225,6,6,1100,1,238,225,104,0,1102,16,13,225,1001,88,68,224,101,-114,224,224,4,224,1002,223,8,223,1001,224,2,224,1,223,224,223,1101,8,76,224,101,-84,224,224,4,224,102,8,223,223,101,1,224,224,1,224,223,223,1101,63,58,225,1102,14,56,224,101,-784,224,224,4,224,102,8,223,223,101,4,224,224,1,223,224,223,1101,29,46,225,102,60,187,224,101,-2340,224,224,4,224,102,8,223,223,101,3,224,224,1,224,223,223,1102,60,53,225,1101,50,52,225,2,14,218,224,101,-975,224,224,4,224,102,8,223,223,1001,224,3,224,1,223,224,223,1002,213,79,224,101,-2291,224,224,4,224,102,8,223,223,1001,224,2,224,1,223,224,223,1,114,117,224,101,-103,224,224,4,224,1002,223,8,223,101,4,224,224,1,224,223,223,1101,39,47,225,101,71,61,224,101,-134,224,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,1102,29,13,225,1102,88,75,225,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1107,677,677,224,102,2,223,223,1006,224,329,1001,223,1,223,108,677,677,224,1002,223,2,223,1005,224,344,101,1,223,223,1008,226,226,224,102,2,223,223,1006,224,359,1001,223,1,223,1107,226,677,224,102,2,223,223,1006,224,374,1001,223,1,223,8,677,226,224,102,2,223,223,1006,224,389,101,1,223,223,8,226,226,224,102,2,223,223,1006,224,404,101,1,223,223,7,677,677,224,1002,223,2,223,1006,224,419,101,1,223,223,7,677,226,224,1002,223,2,223,1005,224,434,101,1,223,223,1108,677,226,224,1002,223,2,223,1006,224,449,1001,223,1,223,108,677,226,224,1002,223,2,223,1006,224,464,101,1,223,223,1108,226,677,224,1002,223,2,223,1006,224,479,101,1,223,223,1007,677,677,224,1002,223,2,223,1006,224,494,1001,223,1,223,107,226,226,224,102,2,223,223,1005,224,509,1001,223,1,223,1008,677,226,224,102,2,223,223,1005,224,524,1001,223,1,223,1007,226,226,224,102,2,223,223,1006,224,539,101,1,223,223,1108,677,677,224,102,2,223,223,1005,224,554,1001,223,1,223,1008,677,677,224,1002,223,2,223,1006,224,569,101,1,223,223,1107,677,226,224,1002,223,2,223,1006,224,584,1001,223,1,223,7,226,677,224,102,2,223,223,1005,224,599,101,1,223,223,108,226,226,224,1002,223,2,223,1005,224,614,101,1,223,223,107,226,677,224,1002,223,2,223,1005,224,629,1001,223,1,223,107,677,677,224,1002,223,2,223,1006,224,644,101,1,223,223,1007,677,226,224,1002,223,2,223,1006,224,659,101,1,223,223,8,226,677,224,102,2,223,223,1005,224,674,1001,223,1,223,4,223,99,226 |
@ -0,0 +1,10 @@ |
|||
use crate::intcode::IntCode; |
|||
use std::io::BufRead; |
|||
|
|||
pub fn part1<F: BufRead> (mut input: F) { |
|||
let mut buf = String::new(); |
|||
let _num_bytes = input.read_line(&mut buf).expect("Unable to first read line of input file"); |
|||
let mut intcode = IntCode::from_str(&buf); |
|||
println!("Input value `1` for part 1 and `5` for part 2:"); |
|||
let _res = intcode.run(); |
|||
} |
@ -0,0 +1,244 @@ |
|||
pub struct IntCode { |
|||
addr_ptr: usize, |
|||
memory: Vec<isize>, |
|||
} |
|||
|
|||
pub struct Value { |
|||
value: isize, |
|||
address: Option<usize>, |
|||
} |
|||
|
|||
struct Op { |
|||
argc: u8, |
|||
argv: Vec<Value>, |
|||
function: OpCodeFn, |
|||
} |
|||
|
|||
pub enum ResultAction { |
|||
None, |
|||
Terminate, |
|||
Write { |
|||
address: usize, |
|||
value: isize, |
|||
}, |
|||
Jump { |
|||
address: usize, |
|||
} |
|||
} |
|||
|
|||
enum ParamMode { |
|||
Position, |
|||
Imediate |
|||
} |
|||
|
|||
type OpCodeFn = fn(&Vec<Value>) -> ResultAction; |
|||
|
|||
impl ParamMode { |
|||
fn from_int(mode: usize) -> Self { |
|||
match mode { |
|||
0 => ParamMode::Position, |
|||
1 => ParamMode::Imediate, |
|||
_ => panic!("Unknown parameter mode {}", mode) |
|||
} |
|||
} |
|||
} |
|||
|
|||
impl IntCode { |
|||
pub fn from_vec(v: Vec<isize>) -> Self { |
|||
IntCode { |
|||
memory: v, |
|||
addr_ptr: 0 |
|||
} |
|||
} |
|||
|
|||
pub fn from_str(s: &str) -> Self { |
|||
Self::from_vec(s.trim().split(",").filter_map(|n| n.parse().ok()).collect()) |
|||
} |
|||
|
|||
fn get_op_modes(&mut self) -> (u8, Vec<ParamMode>) { |
|||
let code = self.read_next(); |
|||
let op = (code % 100) as u8; |
|||
let mut modes = code / 100; |
|||
let mut vmodes = Vec::new(); |
|||
|
|||
while modes > 0 { |
|||
vmodes.push(ParamMode::from_int(modes as usize % 10)); |
|||
modes = modes / 10; |
|||
} |
|||
(op, vmodes) |
|||
} |
|||
|
|||
fn read_next(&mut self) -> isize { |
|||
self.addr_ptr += 1; |
|||
self.memory[self.addr_ptr - 1] |
|||
} |
|||
|
|||
fn read(&self, address: usize) -> isize { |
|||
self.memory[address] |
|||
} |
|||
|
|||
fn write(&mut self, address: usize, value: isize) { |
|||
self.memory[address] = value; |
|||
} |
|||
|
|||
fn jump(&mut self, address: usize) { |
|||
self.addr_ptr = address; |
|||
} |
|||
|
|||
pub fn run(&mut self) -> isize { |
|||
loop { |
|||
let op = Op::from_intcode(self); |
|||
let res = op.run(); |
|||
|
|||
match res { |
|||
ResultAction::Write { address, value } => self.write(address, value), |
|||
ResultAction::Jump { address } => self.jump(address), |
|||
ResultAction::None => (), |
|||
ResultAction::Terminate => break, |
|||
} |
|||
} |
|||
|
|||
self.read(0) |
|||
} |
|||
} |
|||
|
|||
impl Op { |
|||
fn from_intcode(intcode: &mut IntCode) -> Self { |
|||
let (code, vmodes) = intcode.get_op_modes(); |
|||
let mut op = Op::from_code(code); |
|||
for idx in 0..(op.argc) { |
|||
let code = intcode.read_next(); |
|||
let arg = match vmodes.get(idx as usize).unwrap_or(&ParamMode::Position) { |
|||
ParamMode::Position => { |
|||
let value = intcode.read(code as usize); |
|||
Value { address: Some(code as usize), value } |
|||
}, |
|||
ParamMode::Imediate => Value { address: None, value: code } |
|||
}; |
|||
op.argv.push(arg); |
|||
} |
|||
op |
|||
} |
|||
|
|||
fn from_code(code: u8) -> Self { |
|||
match code { |
|||
1 => Self::new(3, ops::add), |
|||
2 => Self::new(3, ops::mul), |
|||
3 => Self::new(1, ops::cin), |
|||
4 => Self::new(1, ops::cout), |
|||
5 => Self::new(2, ops::jump_if_true), |
|||
6 => Self::new(2, ops::jump_if_false), |
|||
7 => Self::new(3, ops::lt), |
|||
8 => Self::new(3, ops::eq), |
|||
99 => Self::new(0, ops::exit), |
|||
c => panic!("Unknown opcode {}", c) |
|||
} |
|||
} |
|||
|
|||
fn new(argc: u8, function: OpCodeFn) -> Self { |
|||
Op { |
|||
argc, |
|||
argv: Vec::new(), |
|||
function, |
|||
} |
|||
} |
|||
|
|||
fn run(&self) -> ResultAction { |
|||
(self.function)(&self.argv) |
|||
} |
|||
} |
|||
|
|||
mod ops { |
|||
use super::{Value, ResultAction}; |
|||
use std::io; |
|||
|
|||
pub fn add(argv: &Vec<Value>) -> ResultAction { |
|||
ResultAction::Write { |
|||
address: argv[2].address.unwrap(), |
|||
value: (argv[0].value + argv[1].value) as isize |
|||
} |
|||
} |
|||
|
|||
pub fn mul(argv: &Vec<Value>) -> ResultAction { |
|||
ResultAction::Write { |
|||
address: argv[2].address.unwrap(), |
|||
value: (argv[0].value * argv[1].value) as isize |
|||
} |
|||
} |
|||
|
|||
pub fn exit(_argv: &Vec<Value>) -> ResultAction { |
|||
ResultAction::Terminate |
|||
} |
|||
|
|||
pub fn cin(argv: &Vec<Value>) -> ResultAction { |
|||
let mut value = String::new(); |
|||
let _ = io::stdin() |
|||
.read_line(&mut value) |
|||
.expect("Unable to read stdin"); |
|||
ResultAction::Write { |
|||
address: argv[0].address.unwrap(), |
|||
value: value.trim().parse().unwrap(), |
|||
} |
|||
} |
|||
|
|||
pub fn cout(argv: &Vec<Value>) -> ResultAction { |
|||
println!("{}", argv[0].value); |
|||
ResultAction::None |
|||
} |
|||
|
|||
pub fn jump_if_true(argv: &Vec<Value>) -> ResultAction { |
|||
if argv[0].value != 0 { |
|||
ResultAction::Jump { address: argv[1].value as usize } |
|||
} else { |
|||
ResultAction::None |
|||
} |
|||
} |
|||
|
|||
pub fn jump_if_false(argv: &Vec<Value>) -> ResultAction { |
|||
if argv[0].value == 0 { |
|||
ResultAction::Jump { address: argv[1].value as usize } |
|||
} else { |
|||
ResultAction::None |
|||
} |
|||
} |
|||
|
|||
pub fn lt(argv: &Vec<Value>) -> ResultAction { |
|||
ResultAction::Write { |
|||
address: argv[2].address.unwrap(), |
|||
value: if argv[0].value < argv[1].value { 1 } else { 0 } |
|||
} |
|||
} |
|||
|
|||
pub fn eq(argv: &Vec<Value>) -> ResultAction { |
|||
ResultAction::Write { |
|||
address: argv[2].address.unwrap(), |
|||
value: if argv[0].value == argv[1].value { 1 } else { 0 } |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
#[cfg(test)] |
|||
mod test { |
|||
use super::*; |
|||
|
|||
#[test] |
|||
fn test_run_intcode_position_mode() { |
|||
let input1 = vec![1, 0, 0, 0, 99]; |
|||
let input2 = vec![2, 0, 5, 0, 99, 3]; |
|||
|
|||
let mut intcode = IntCode::from_vec(input1); |
|||
assert_eq!(intcode.run(), 2); |
|||
intcode = IntCode::from_vec(input2); |
|||
assert_eq!(intcode.run(), 6); |
|||
} |
|||
|
|||
#[test] |
|||
fn test_run_intcode_imediate_mode() { |
|||
let input = vec![1002, 4, 3, 4, 33]; |
|||
|
|||
let mut intcode = IntCode::from_vec(input); |
|||
intcode.run(); |
|||
assert_eq!(99, intcode.memory[4]); |
|||
} |
|||
} |
Loading…
Reference in new issue