day09 prepared IntCodeComputer to use HashSet memory and new intructions

This commit is contained in:
Johannes
2019-12-09 23:01:55 +01:00
parent 676fb13a59
commit 2dc626e227
4 changed files with 113 additions and 63 deletions

View File

@@ -1,5 +1,5 @@
mod tasks; mod tasks;
fn main() { fn main() {
tasks::day05::run(); tasks::day09::run();
} }

View File

@@ -1,19 +1,25 @@
use std::collections::HashMap;
pub type RAM = HashMap<usize, i128>;
#[allow(dead_code)] #[allow(dead_code)]
pub fn run() { pub fn run() {
let input = std::fs::read_to_string("input/day05.txt").unwrap(); let input = std::fs::read_to_string("input/day05.txt").unwrap();
let ram: Vec<i32> = input let ram: RAM = input
.split(",") .split(",")
.map(|s| s.parse::<i32>().unwrap()) .enumerate()
.map(|(i, s)| (i, s.parse::<i128>().unwrap()))
.collect(); .collect();
task1(ram.clone()); task1(ram.clone());
task2(ram.clone()); task2(ram.clone());
} }
pub struct IntCodeComputer { pub struct IntCodeComputer {
input_storage: Vec<i32>, input_storage: Vec<i128>,
output_storage: Vec<i32>, output_storage: Vec<i128>,
pc: usize, pc: usize,
ram: Vec<i32>, ram: RAM,
relative_base_offset: i128,
} }
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
@@ -26,35 +32,44 @@ enum OpCode {
JumpIfFalse, JumpIfFalse,
LessThan, LessThan,
Equals, Equals,
AdjustRelBase,
Terminate, Terminate,
} }
#[derive(Debug)] #[derive(Debug)]
enum OpParam { enum OpParam {
Immediate(i32), Immediate(i128),
Memory(usize), Memory(usize),
Relative(i128),
} }
impl OpParam { impl OpParam {
fn from(val: i32, type_number: i32) -> Self { fn from(val: i128, type_number: i128) -> Self {
match type_number { match type_number {
0 => OpParam::Memory(val as usize), 0 => OpParam::Memory(val as usize),
1 => OpParam::Immediate(val), 1 => OpParam::Immediate(val),
2 => OpParam::Relative(val),
_ => unreachable!("unexpected parameter"), _ => unreachable!("unexpected parameter"),
} }
} }
fn retrieve(&self, memory: &Vec<i32>) -> i32 { fn retrieve(&self, memory: &RAM, relative_base_offset: i128) -> i128 {
match self { match self {
OpParam::Immediate(v) => *v, OpParam::Immediate(v) => *v,
OpParam::Memory(i) => memory[*i], OpParam::Memory(i) => memory.get_default(*i),
OpParam::Relative(i) => memory.get_default((relative_base_offset + *i) as usize),
} }
} }
fn store(&self, memory: &mut Vec<i32>, value: i32) { fn store(&self, memory: &mut RAM, value: i128, relative_base_offset: i128) {
match self { match self {
OpParam::Immediate(_) => panic!("cannot save to immediate position"), OpParam::Immediate(_) => panic!("cannot save to immediate position"),
OpParam::Memory(i) => memory[*i] = value, OpParam::Memory(i) => {
memory.insert(*i, value);
}
OpParam::Relative(i) => {
memory.insert((relative_base_offset + *i) as usize, value);
}
} }
} }
} }
@@ -66,9 +81,9 @@ struct Op {
} }
impl Op { impl Op {
fn from(pc: usize, memory: &Vec<i32>) -> Self { fn from(pc: usize, memory: &RAM) -> Self {
//opcode: 123xx -> 1, 2, 3: parameter type for parameters 1-3, xx = actual op code //opcode: 123xx -> 1, 2, 3: parameter type for parameters 1-3, xx = actual op code
let mut opcode = memory[pc]; let mut opcode = memory.get_default(pc);
let p_type1 = opcode / 10_000; let p_type1 = opcode / 10_000;
opcode %= 10_000; opcode %= 10_000;
let p_type2 = opcode / 1000; let p_type2 = opcode / 1000;
@@ -79,57 +94,61 @@ impl Op {
1 => Op { 1 => Op {
opcode: OpCode::Add, opcode: OpCode::Add,
params: vec![ params: vec![
OpParam::from(memory[pc + 1], p_type3), OpParam::from(memory.get_default(pc + 1), p_type3),
OpParam::from(memory[pc + 2], p_type2), OpParam::from(memory.get_default(pc + 2), p_type2),
OpParam::from(memory[pc + 3], p_type1), OpParam::from(memory.get_default(pc + 3), p_type1),
], ],
}, },
2 => Op { 2 => Op {
opcode: OpCode::Multiply, opcode: OpCode::Multiply,
params: vec![ params: vec![
OpParam::from(memory[pc + 1], p_type3), OpParam::from(memory.get_default(pc + 1), p_type3),
OpParam::from(memory[pc + 2], p_type2), OpParam::from(memory.get_default(pc + 2), p_type2),
OpParam::from(memory[pc + 3], p_type1), OpParam::from(memory.get_default(pc + 3), p_type1),
], ],
}, },
3 => Op { 3 => Op {
opcode: OpCode::Input, opcode: OpCode::Input,
params: vec![OpParam::from(memory[pc + 1], p_type3)], params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)],
}, },
4 => Op { 4 => Op {
opcode: OpCode::Output, opcode: OpCode::Output,
params: vec![OpParam::from(memory[pc + 1], p_type3)], params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)],
}, },
5 => Op { 5 => Op {
opcode: OpCode::JumpIfTrue, opcode: OpCode::JumpIfTrue,
params: vec![ params: vec![
OpParam::from(memory[pc + 1], p_type3), OpParam::from(memory.get_default(pc + 1), p_type3),
OpParam::from(memory[pc + 2], p_type2), OpParam::from(memory.get_default(pc + 2), p_type2),
], ],
}, },
6 => Op { 6 => Op {
opcode: OpCode::JumpIfFalse, opcode: OpCode::JumpIfFalse,
params: vec![ params: vec![
OpParam::from(memory[pc + 1], p_type3), OpParam::from(memory.get_default(pc + 1), p_type3),
OpParam::from(memory[pc + 2], p_type2), OpParam::from(memory.get_default(pc + 2), p_type2),
], ],
}, },
7 => Op { 7 => Op {
opcode: OpCode::LessThan, opcode: OpCode::LessThan,
params: vec![ params: vec![
OpParam::from(memory[pc + 1], p_type3), OpParam::from(memory.get_default(pc + 1), p_type3),
OpParam::from(memory[pc + 2], p_type2), OpParam::from(memory.get_default(pc + 2), p_type2),
OpParam::from(memory[pc + 3], p_type1), OpParam::from(memory.get_default(pc + 3), p_type1),
], ],
}, },
8 => Op { 8 => Op {
opcode: OpCode::Equals, opcode: OpCode::Equals,
params: vec![ params: vec![
OpParam::from(memory[pc + 1], p_type3), OpParam::from(memory.get_default(pc + 1), p_type3),
OpParam::from(memory[pc + 2], p_type2), OpParam::from(memory.get_default(pc + 2), p_type2),
OpParam::from(memory[pc + 3], p_type1), OpParam::from(memory.get_default(pc + 3), p_type1),
], ],
}, },
9 => Op {
opcode: OpCode::AdjustRelBase,
params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)],
},
99 => Op { 99 => Op {
opcode: OpCode::Terminate, opcode: OpCode::Terminate,
params: vec![], params: vec![],
@@ -140,12 +159,13 @@ impl Op {
} }
impl IntCodeComputer { impl IntCodeComputer {
pub fn new(input: Vec<i32>, memory: Vec<i32>) -> Self { pub fn new(input: Vec<i128>, memory: RAM) -> Self {
IntCodeComputer { IntCodeComputer {
input_storage: input, input_storage: input,
output_storage: Vec::new(), output_storage: Vec::new(),
pc: 0, pc: 0,
ram: memory, ram: memory,
relative_base_offset: 0,
} }
} }
@@ -164,60 +184,73 @@ impl IntCodeComputer {
while op.opcode != OpCode::Terminate { while op.opcode != OpCode::Terminate {
match op.opcode { match op.opcode {
OpCode::Add => { OpCode::Add => {
let r = op.params[0].retrieve(&self.ram) + op.params[1].retrieve(&self.ram); let r = op.params[0].retrieve(&self.ram, self.relative_base_offset)
op.params[2].store(&mut self.ram, r); + op.params[1].retrieve(&self.ram, self.relative_base_offset);
op.params[2].store(&mut self.ram, r, self.relative_base_offset);
self.pc += 4; self.pc += 4;
} }
OpCode::Multiply => { OpCode::Multiply => {
let r = op.params[0].retrieve(&self.ram) * op.params[1].retrieve(&self.ram); let r = op.params[0].retrieve(&self.ram, self.relative_base_offset)
op.params[2].store(&mut self.ram, r); * op.params[1].retrieve(&self.ram, self.relative_base_offset);
op.params[2].store(&mut self.ram, r, self.relative_base_offset);
self.pc += 4; self.pc += 4;
} }
OpCode::Input => { OpCode::Input => {
if let Some(v) = inputs.next() { if let Some(v) = inputs.next() {
op.params[0].store(&mut self.ram, *v); op.params[0].store(&mut self.ram, *v, self.relative_base_offset);
self.pc += 2; self.pc += 2;
} else { } else {
return false; return false;
} }
} }
OpCode::Output => { OpCode::Output => {
self.output_storage.push(op.params[0].retrieve(&self.ram)); self.output_storage
.push(op.params[0].retrieve(&self.ram, self.relative_base_offset));
self.pc += 2; self.pc += 2;
} }
OpCode::JumpIfTrue => { OpCode::JumpIfTrue => {
if op.params[0].retrieve(&self.ram) > 0 { if op.params[0].retrieve(&self.ram, self.relative_base_offset) > 0 {
self.pc = op.params[1].retrieve(&self.ram) as usize; self.pc =
op.params[1].retrieve(&self.ram, self.relative_base_offset) as usize;
} else { } else {
self.pc += 3; self.pc += 3;
} }
} }
OpCode::JumpIfFalse => { OpCode::JumpIfFalse => {
if op.params[0].retrieve(&self.ram) == 0 { if op.params[0].retrieve(&self.ram, self.relative_base_offset) == 0 {
self.pc = op.params[1].retrieve(&self.ram) as usize; self.pc =
op.params[1].retrieve(&self.ram, self.relative_base_offset) as usize;
} else { } else {
self.pc += 3; self.pc += 3;
} }
} }
OpCode::LessThan => { OpCode::LessThan => {
let r = if op.params[0].retrieve(&self.ram) < op.params[1].retrieve(&self.ram) { let r = if op.params[0].retrieve(&self.ram, self.relative_base_offset)
1 < op.params[1].retrieve(&self.ram, self.relative_base_offset)
} else {
0
};
op.params[2].store(&mut self.ram, r);
self.pc += 4;
}
OpCode::Equals => {
let r = if op.params[0].retrieve(&self.ram) == op.params[1].retrieve(&self.ram)
{ {
1 1
} else { } else {
0 0
}; };
op.params[2].store(&mut self.ram, r); op.params[2].store(&mut self.ram, r, self.relative_base_offset);
self.pc += 4; self.pc += 4;
} }
OpCode::Equals => {
let r = if op.params[0].retrieve(&self.ram, self.relative_base_offset)
== op.params[1].retrieve(&self.ram, self.relative_base_offset)
{
1
} else {
0
};
op.params[2].store(&mut self.ram, r, self.relative_base_offset);
self.pc += 4;
}
OpCode::AdjustRelBase => {
self.relative_base_offset +=
op.params[0].retrieve(&self.ram, self.relative_base_offset);
self.pc += 2;
}
OpCode::Terminate => {} OpCode::Terminate => {}
} }
op = Op::from(self.pc, &self.ram); op = Op::from(self.pc, &self.ram);
@@ -225,7 +258,7 @@ impl IntCodeComputer {
return true; return true;
} }
pub fn set_input(&mut self, input: &[i32]) { pub fn set_input(&mut self, input: &[i128]) {
self.input_storage.clear(); self.input_storage.clear();
for x in input { for x in input {
self.input_storage.push(*x); self.input_storage.push(*x);
@@ -236,21 +269,31 @@ impl IntCodeComputer {
self.output_storage.clear(); self.output_storage.clear();
} }
pub fn get_output(&self) -> &[i32] { pub fn get_output(&self) -> &[i128] {
self.output_storage.as_slice() self.output_storage.as_slice()
} }
} }
fn task1(ram: Vec<i32>) { fn task1(ram: RAM) {
let mut computer = IntCodeComputer::new(vec![1], ram); let mut computer = IntCodeComputer::new(vec![1], ram);
computer.run_until_end(); computer.run_until_end();
println!("{:?}", computer.get_output()); println!("{:?}", computer.get_output());
println!("Task 1: {}", computer.get_output().last().unwrap()); println!("Task 1: {}", computer.get_output().last().unwrap());
} }
fn task2(ram: Vec<i32>) { fn task2(ram: RAM) {
let mut computer = IntCodeComputer::new(vec![5], ram); let mut computer = IntCodeComputer::new(vec![5], ram);
computer.run_until_end(); computer.run_until_end();
println!("{:?}", computer.get_output()); println!("{:?}", computer.get_output());
println!("Task 2: {}", computer.get_output().last().unwrap()); println!("Task 2: {}", computer.get_output().last().unwrap());
} }
trait Easy {
fn get_default(&self, index: usize) -> i128;
}
impl Easy for RAM {
fn get_default(&self, index: usize) -> i128 {
**self.get(&index).get_or_insert(&0)
}
}

View File

@@ -6,20 +6,23 @@ pub fn run() {
let prog_code: Vec<_> = std::fs::read_to_string("input/day07.txt") let prog_code: Vec<_> = std::fs::read_to_string("input/day07.txt")
.unwrap() .unwrap()
.split(",") .split(",")
.map(|s| s.parse::<i32>().unwrap()) .map(|s| s.parse::<i128>().unwrap())
.collect(); .collect();
task1(prog_code.clone()); task1(prog_code.clone());
task2(prog_code.clone()); task2(prog_code.clone());
} }
fn task1(input: Vec<i32>) { fn task1(input: Vec<i128>) {
let phases = vec![0, 1, 2, 3, 4]; let phases = vec![0, 1, 2, 3, 4];
let result = phases let result = phases
.iter() .iter()
.permutations(phases.len()) .permutations(phases.len())
.map(|perm| { .map(|perm| {
perm.iter().fold(0, |signal, phase| { perm.iter().fold(0, |signal, phase| {
let mut computer = IntCodeComputer::new(vec![**phase, signal], input.clone()); let mut computer = IntCodeComputer::new(
vec![**phase, signal],
input.clone().into_iter().enumerate().collect(),
);
computer.run_until_end(); computer.run_until_end();
*computer.get_output().last().unwrap() *computer.get_output().last().unwrap()
}) })
@@ -28,7 +31,7 @@ fn task1(input: Vec<i32>) {
println!("Task 1: best signal is {}", result.unwrap()); println!("Task 1: best signal is {}", result.unwrap());
} }
fn task2(input: Vec<i32>) { fn task2(input: Vec<i128>) {
let phases = vec![5, 6, 7, 8, 9]; let phases = vec![5, 6, 7, 8, 9];
let result = phases let result = phases
.iter() .iter()
@@ -37,7 +40,10 @@ fn task2(input: Vec<i32>) {
let mut machines: Vec<IntCodeComputer> = perm let mut machines: Vec<IntCodeComputer> = perm
.iter() .iter()
.map(|phase| { .map(|phase| {
let mut comp = IntCodeComputer::new(vec![**phase], input.clone()); let mut comp = IntCodeComputer::new(
vec![**phase],
input.clone().into_iter().enumerate().collect(),
);
comp.run_until_input_empty(); comp.run_until_input_empty();
comp comp
}) })

View File

@@ -5,3 +5,4 @@ pub mod day05;
pub mod day06; pub mod day06;
pub mod day07; pub mod day07;
pub mod day08; pub mod day08;
pub mod day09;