day9 part2

This commit is contained in:
Stefan Schwarz 2020-04-21 23:38:00 +02:00
parent 7277571162
commit 4e908b8bf9
2 changed files with 445 additions and 1 deletions

View file

@ -28,4 +28,8 @@ path = "src/day5/main.rs"
[[bin]]
name = "day7"
path = "src/day7/main.rs"
path = "src/day7/main.rs"
[[bin]]
name = "day9"
path = "src/day9/main.rs"

440
src/day9/main.rs Normal file
View file

@ -0,0 +1,440 @@
use std::collections::VecDeque;
use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader};
#[derive(Copy, Clone)]
enum Var {
A = 1,
B,
C,
}
#[derive(Copy, Clone, Debug)]
enum Mode {
Position,
Immediate,
Relative,
}
impl Default for Mode {
fn default() -> Self {
Mode::Position
}
}
impl From<i64> for Mode {
fn from(b: i64) -> Self {
match b {
0 => Mode::Position,
1 => Mode::Immediate,
2 => Mode::Relative,
_ => panic!("invalid mode {}", b),
}
}
}
#[derive(Copy, Clone, Default, Debug)]
struct Modes {
a: Mode,
b: Mode,
c: Mode,
}
impl Modes {
fn mode_for(&self, v: &Var) -> Mode {
match v {
Var::A => self.a,
Var::B => self.b,
Var::C => self.c,
}
}
}
impl From<(Mode, Mode, Mode)> for Modes {
fn from(modes: (Mode, Mode, Mode)) -> Self {
Modes {
a: modes.0,
b: modes.1,
c: modes.2,
}
}
}
impl From<&ModedOpcode> for Modes {
fn from(mo: &ModedOpcode) -> Self {
mo.modes
}
}
#[derive(Copy, Clone)]
enum Opcode {
Add,
Multiply,
Input,
Output,
JumpIfTrue,
JumpIfFalse,
LessThan,
Equals,
RelativeAdj,
Halt,
}
impl From<&ModedOpcode> for Opcode {
fn from(mo: &ModedOpcode) -> Self {
mo.op
}
}
impl From<i64> for Opcode {
fn from(i: i64) -> Self {
match i {
1 => Opcode::Add,
2 => Opcode::Multiply,
3 => Opcode::Input,
4 => Opcode::Output,
5 => Opcode::JumpIfTrue,
6 => Opcode::JumpIfFalse,
7 => Opcode::LessThan,
8 => Opcode::Equals,
9 => Opcode::RelativeAdj,
99 => Opcode::Halt,
_ => panic!("invalid opcode {}", i),
}
}
}
struct ModedOpcode {
modes: Modes,
op: Opcode,
}
impl From<i64> for ModedOpcode {
fn from(i: i64) -> Self {
let code = i % 100;
let modes = i / 100;
let a = (modes % 10) / 1;
let b = (modes % 100) / 10;
let c = (modes % 1000) / 100;
let modes = (Mode::from(a), Mode::from(b), Mode::from(c));
ModedOpcode {
modes: Modes::from(modes),
op: Opcode::from(code),
}
}
}
struct Computer {
pos: usize,
rel: i64,
program: Vec<i64>,
modes: Modes,
inputs: VecDeque<i64>,
outputs: VecDeque<i64>,
halted: bool,
}
impl Clone for Computer {
fn clone(&self) -> Self {
Computer::from(self.program.clone())
}
}
impl From<File> for Computer {
fn from(f: File) -> Self {
let f = BufReader::new(f);
let program: Vec<i64> = f
.split(b',')
.map(|o| {
let o = o.unwrap();
let mut o = o.iter().peekable();
let sign = if o.peek() == Some(&&b'-') { -1 } else { 1 };
o.filter(|i| **i >= b'0' && **i <= b'9')
.fold(0, |s, i| ((i - b'0') as i64 + 10 * s))
* sign
})
.collect();
Computer::from(program)
}
}
impl From<Vec<i64>> for Computer {
fn from(program: Vec<i64>) -> Self {
Computer {
pos: 0,
rel: 0,
program: program,
modes: Default::default(),
inputs: VecDeque::new(),
outputs: VecDeque::new(),
halted: false,
}
}
}
impl Computer {
fn clone_with_modified_program(&self, u: Vec<(usize, i64)>) -> Computer {
let mut computer = self.clone();
for (pos, val) in u {
computer.program[pos] = val;
}
computer
}
fn clone_with_input(&self, input: Vec<i64>) -> Computer {
let mut computer = self.clone();
computer.inputs = VecDeque::from(input);
computer
}
fn run(&mut self) {
while !self.halted {
self.step();
}
}
fn run_until_output(&mut self) -> Option<i64> {
loop {
self.step();
if self.outputs.len() > 0 {
return self.outputs.pop_front();
}
if self.halted {
return None;
}
}
}
fn run_must_output(&mut self) -> i64 {
self.run_until_output()
.expect("computer halted without output")
}
fn run_io(&mut self, input: Vec<i64>) -> Option<i64> {
input.iter().for_each(|i| self.inputs.push_back(*i));
self.run_until_output()
}
fn step(&mut self) {
let instruction = self.program[self.pos];
let instruction = ModedOpcode::from(instruction);
self.modes = Modes::from(&instruction);
let advance = match Opcode::from(&instruction) {
Opcode::Add => self.add(),
Opcode::Multiply => self.multiply(),
Opcode::Input => self.input(),
Opcode::Output => self.output(),
Opcode::JumpIfTrue => self.jump_if_true(),
Opcode::JumpIfFalse => self.jump_if_false(),
Opcode::LessThan => self.less_than(),
Opcode::Equals => self.equals(),
Opcode::RelativeAdj => self.relative_adj(),
Opcode::Halt => self.halt(),
};
self.pos += advance;
}
fn get_pos(&self, pos: usize) -> i64 {
*self.program.get(pos).unwrap_or(&0)
}
fn get(&self, v: &Var) -> i64 {
let want = self.pos + *v as usize;
let want = match self.modes.mode_for(v) {
Mode::Position => self.get_pos(want as usize) as usize,
Mode::Immediate => want,
Mode::Relative => (self.rel + self.get_pos(want)) as usize,
};
self.get_pos(want)
}
fn get_a(&self) -> i64 {
self.get(&Var::A)
}
fn get_b(&self) -> i64 {
self.get(&Var::B)
}
fn set(&mut self, v: &Var, value: i64) {
let length = self.program.len();
let want = self.pos + *v as usize;
let want = match self.modes.mode_for(v) {
Mode::Position => self.get_pos(want) as usize,
Mode::Immediate => want,
Mode::Relative => (self.rel + self.get_pos(want)) as usize,
};
if length < want {
let missing = (want - length) + 5;
self.program.extend_from_slice(&vec![0; missing])
}
self.program[want] = value;
}
fn set_a(&mut self, value: i64) {
self.set(&Var::A, value)
}
fn set_c(&mut self, value: i64) {
self.set(&Var::C, value)
}
fn add(&mut self) -> usize {
self.set_c(self.get_a() + self.get_b());
4
}
fn multiply(&mut self) -> usize {
self.set_c(self.get_a() * self.get_b());
4
}
fn input(&mut self) -> usize {
let value = self.inputs.pop_front().expect("no input provided");
self.set_a(value);
2
}
fn output(&mut self) -> usize {
self.outputs.push_back(self.get_a());
2
}
fn jump_if_true(&mut self) -> usize {
if self.get_a() > 0 {
self.pos = self.get_b() as usize;
return 0;
}
3
}
fn jump_if_false(&mut self) -> usize {
if self.get_a() == 0 {
self.pos = self.get_b() as usize;
return 0;
}
3
}
fn less_than(&mut self) -> usize {
if self.get_a() < self.get_b() {
self.set_c(1)
} else {
self.set_c(0)
}
4
}
fn equals(&mut self) -> usize {
if self.get_a() == self.get_b() {
self.set_c(1)
} else {
self.set_c(0)
}
4
}
fn relative_adj(&mut self) -> usize {
self.rel = self.rel + self.get_a();
2
}
fn halt(&mut self) -> usize {
self.halted = true;
0
}
}
fn main() -> io::Result<()> {
let filename = env::args().nth(1).expect("provide file as first param");
let computer = Computer::from(File::open(filename)?);
// part1
let result = computer.clone_with_input(vec![1]).run_must_output();
println!("{:?}", result);
// part2
let result = computer.clone_with_input(vec![2]).run_must_output();
println!("{:?}", result);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn example1() {
let program = vec![
109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99,
];
let mut computer = Computer::from(program.clone());
computer.run();
assert_eq!(Vec::from(computer.outputs), program)
}
#[test]
fn example2() {
assert_eq!(
Computer::from(vec![1102, 34915192, 34915192, 7, 4, 7, 99, 0]).run_must_output(),
1219070632396864
)
}
#[test]
fn example3() {
assert_eq!(
Computer::from(vec![104, 1125899906842624, 99]).run_must_output(),
1125899906842624
)
}
#[test]
fn day5exampe1() {
let computer = Computer::from(vec![3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8]);
assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
}
#[test]
fn day5exampe2() {
let computer = Computer::from(vec![3, 3, 1108, -1, 8, 3, 4, 3, 99]);
assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
}
#[test]
fn day5exampe3() {
let computer = Computer::from(vec![
3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9,
]);
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
let computer = Computer::from(vec![3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1]);
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
}
#[test]
fn day5exampe4() {
let computer = Computer::from(vec![
3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36, 98, 0,
0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000, 1, 20, 4,
20, 1105, 1, 46, 98, 99,
]);
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 999);
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1000);
assert_eq!(computer.clone_with_input(vec![9]).run_must_output(), 1001);
}
#[test]
fn day9part1() {
let computer = Computer::from(File::open("input9").unwrap());
assert_eq!(
computer.clone_with_input(vec![1]).run_must_output(),
3063082071
);
}
}