This commit is contained in:
Armin Friedl 2019-12-07 18:57:42 +01:00
parent c944c2a758
commit e361844dd9
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
3 changed files with 1019 additions and 0 deletions

11
day5/2/Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "intcode"
version = "0.1.0"
authors = ["Armin Friedl <dev@friedl.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4"
env_logger="0.7"

678
day5/2/input Normal file
View file

@ -0,0 +1,678 @@
3
225
1
225
6
6
1100
1
238
225
104
0
1101
90
60
224
1001
224
-150
224
4
224
1002
223
8
223
1001
224
7
224
1
224
223
223
1
57
83
224
1001
224
-99
224
4
224
1002
223
8
223
1001
224
5
224
1
223
224
223
1102
92
88
225
101
41
187
224
1001
224
-82
224
4
224
1002
223
8
223
101
7
224
224
1
224
223
223
1101
7
20
225
1101
82
64
225
1002
183
42
224
101
-1554
224
224
4
224
102
8
223
223
1001
224
1
224
1
224
223
223
1102
70
30
224
101
-2100
224
224
4
224
102
8
223
223
101
1
224
224
1
224
223
223
2
87
214
224
1001
224
-2460
224
4
224
1002
223
8
223
101
7
224
224
1
223
224
223
102
36
180
224
1001
224
-1368
224
4
224
1002
223
8
223
1001
224
5
224
1
223
224
223
1102
50
38
225
1102
37
14
225
1101
41
20
225
1001
217
7
224
101
-25
224
224
4
224
1002
223
8
223
101
2
224
224
1
224
223
223
1101
7
30
225
1102
18
16
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
7
226
226
224
102
2
223
223
1006
224
329
101
1
223
223
1107
677
226
224
102
2
223
223
1006
224
344
1001
223
1
223
8
677
226
224
1002
223
2
223
1005
224
359
101
1
223
223
107
677
677
224
1002
223
2
223
1006
224
374
101
1
223
223
7
677
226
224
1002
223
2
223
1006
224
389
101
1
223
223
108
677
226
224
1002
223
2
223
1005
224
404
101
1
223
223
1108
677
226
224
102
2
223
223
1005
224
419
101
1
223
223
8
226
677
224
102
2
223
223
1006
224
434
1001
223
1
223
1008
677
677
224
1002
223
2
223
1005
224
449
1001
223
1
223
1107
226
677
224
102
2
223
223
1006
224
464
101
1
223
223
107
226
677
224
1002
223
2
223
1006
224
479
1001
223
1
223
7
226
677
224
102
2
223
223
1005
224
494
1001
223
1
223
8
677
677
224
102
2
223
223
1006
224
509
1001
223
1
223
1108
677
677
224
102
2
223
223
1005
224
524
1001
223
1
223
1108
226
677
224
1002
223
2
223
1005
224
539
101
1
223
223
107
226
226
224
102
2
223
223
1006
224
554
1001
223
1
223
1007
226
226
224
102
2
223
223
1005
224
569
1001
223
1
223
1008
226
226
224
102
2
223
223
1005
224
584
101
1
223
223
1007
677
677
224
1002
223
2
223
1005
224
599
1001
223
1
223
108
677
677
224
1002
223
2
223
1006
224
614
1001
223
1
223
1007
226
677
224
1002
223
2
223
1006
224
629
101
1
223
223
1008
677
226
224
102
2
223
223
1005
224
644
101
1
223
223
1107
226
226
224
1002
223
2
223
1005
224
659
1001
223
1
223
108
226
226
224
1002
223
2
223
1005
224
674
101
1
223
223
4
223
99
226

330
day5/2/src/main.rs Normal file
View file

@ -0,0 +1,330 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use env_logger;
use std::fs::File;
use std::io::{BufReader, BufRead, stdin, stdout, Write};
use std::error::Error;
use std::result::Result;
#[derive(Debug)]
struct Computer {
mem: Vec<i32>,
intp: *mut i32, // here will be dragons
}
#[derive(Debug)]
struct Opcode {
inst: u8,
mode: Vec<Opmode>,
}
#[derive(Debug)]
enum Opmode {
Position,
Immediate
}
impl From<i32> for Opcode {
fn from(num: i32) -> Self {
let mut x = num;
let mut opcode = Opcode {
inst: (num%100) as u8,
mode: Vec::new()
};
x /= 100; // strip 2 least significant digits
loop {
match x%10 {
0 => opcode.mode.push(Opmode::Position),
1 => opcode.mode.push(Opmode::Immediate),
_ => panic!{"Invalid opmode: {}", x%10}
}
x /= 10;
if x == 0 {break}
}
opcode
}
}
#[allow(dead_code)]
impl Computer {
fn new() -> Self {
let mut mem = vec![0];
let intp = &mut mem[0] as *mut i32;
Computer {mem, intp}
}
fn push(&mut self, val: i32) {
if self.mem[0] == 0 { // we are in init state
self.mem[0] = val
} else {
self.mem.push(val);
}
}
fn set(&mut self, pos: usize, val: i32) {
self.mem[pos] = val;
}
fn compute(&mut self) -> i32 {
// first reset the pointer just to be sure
self.intp = &mut self.mem[0] as *mut i32;
loop {
let opcode: Opcode = self._expect_next(&Opmode::Immediate).into();
trace!{"{:?}", opcode}
match opcode.inst {
1 => self._add(&opcode.mode),
2 => self._mul(&opcode.mode),
3 => self._input(),
4 => self._output(&opcode.mode),
5 => self._jump_true(&opcode.mode),
6 => self._jump_false(&opcode.mode),
7 => self._less_than(&opcode.mode),
8 => self._equals(&opcode.mode),
99 => break,
_ => panic!{"Invalid opcode {}", opcode.inst},
}
}
self.mem[0]
}
fn _add(&mut self, modes: &[Opmode]) {
let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position));
let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position));
let pos = self._expect_next(&Opmode::Immediate) as usize;
debug!{"Adding {} and {} to position {}", op1, op2, pos}
self.mem[pos] = op1 + op2;
trace!{"{:?}", self}
}
fn _mul(&mut self, modes: &[Opmode]) {
let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position));
let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position));
let pos = self._expect_next(&Opmode::Immediate) as usize;
debug!{"Multiplying {} and {} to position {}", op1, op2, pos}
self.mem[pos] = op1*op2;
trace!{"{:?}", self}
}
fn _input(&mut self) {
let pos = self._expect_next(&Opmode::Immediate) as usize;
debug!{"Reading input to position {}", pos}
let mut input = String::new();
print!{"Input: "};
stdout().flush().unwrap();
stdin().read_line(&mut input).unwrap();
self.mem[pos] = input.trim().parse().expect("Invalid input");
trace!{"{:?}", self}
}
fn _output(&mut self, modes: &[Opmode]) {
let op = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position));
debug!{"Writing output {}", op}
println!("Output: {}", op);
trace!{"{:?}", self}
}
fn _jump_true(&mut self, modes: &[Opmode]) {
let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position));
let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position));
debug!{"Jump true for op {} to position {}", op1, op2}
if op1 == 0 {return;}
debug!{"Jumping to {}", op2}
self.intp = &mut self.mem[0] as *mut i32; // reset pointer
unsafe {
self.intp = self.intp.offset(op2 as isize);
}
trace!{"{:?}", self}
}
fn _jump_false(&mut self, modes: &[Opmode]) {
let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position));
let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position));
debug!{"Jump false for op {} to position {}", op1, op2}
if op1 != 0 {return;}
self.intp = &mut self.mem[0] as *mut i32; // reset pointer
unsafe {
self.intp = self.intp.offset(op2 as isize);
}
trace!{"{:?}", self}
}
fn _less_than(&mut self, modes: &[Opmode]) {
let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position));
let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position));
let position = self._expect_next(&Opmode::Immediate) as usize;
debug!{"Less than {} < {} writing to position {}", op1, op2, position}
if op1 < op2 {
self.mem[position] = 1;
} else {
self.mem[position] = 0;
}
trace!{"{:?}", self}
}
fn _equals(&mut self, modes: &[Opmode]) {
let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position));
let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position));
let position = self._expect_next(&Opmode::Immediate) as usize;
debug!{"Equals {} == {} writing to position {}", op1, op2, position}
if op1 == op2 {
self.mem[position] = 1;
} else {
self.mem[position] = 0;
}
trace!{"{:?}", self}
}
fn _next(&mut self) -> Option<i32> {
unsafe{ // Dragons
// overflow check, smart cpu
let lstp = self.mem.last_mut().unwrap() as *mut i32;
if self.intp == lstp.offset(1) {
return None;
}
let op = *self.intp;
self.intp = self.intp.offset(1);
Some(op)
}
}
fn _expect_next(&mut self, mode: &Opmode) -> i32 {
let next = self._next().expect("Exhausted");
match mode {
Opmode::Position => {
trace!{"Next in position {} = {}", next, self.mem[next as usize]}
self.mem[next as usize]
},
Opmode::Immediate => {
trace!{"Next in immediate = {}", next}
next
}
}
}
}
impl Clone for Computer {
fn clone(&self) -> Self {
let mut mem = self.mem.clone();
let intp = &mut mem[0] as *mut i32;
Computer { mem, intp }
}
}
fn main() -> Result<(), Box<dyn Error>>{
env_logger::init();
let input = File::open("input")?;
let reader = BufReader::new(input);
let mut computer = Computer::new();
reader.lines()
.filter_map(Result::ok) // transform into Option and filter
.filter_map(|l| l.parse().ok()) // parse String to i32 transform to Option and filter
.for_each(|i| computer.push(i)); // push instruction to computer
computer.compute();
Ok(())
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn tc1() {
env_logger::init();
let mut computer = Computer::new();
let mem = vec![3,9,8,9,10,9,4,9,99,-1,8];
mem.iter().for_each(|&n| computer.push(n));
println!{"{:?}", computer}
computer.compute();
println!{"{:?}", computer}
}
#[test]
fn tc2() {
env_logger::init();
let mut computer = Computer::new();
let mem = vec![3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9];
mem.iter().for_each(|&n| computer.push(n));
println!{"{:?}", computer}
computer.compute();
println!{"{:?}", computer}
}
#[test]
fn tc3() {
env_logger::init();
let mut computer = Computer::new();
let mem = 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];
mem.iter().for_each(|&n| computer.push(n));
debug!{"{:?}", computer}
computer.compute();
debug!{"{:?}", computer}
}
}
#[cfg(test)]
mod regression {
use super::*;
#[test]
fn tc1() {
let mut computer = Computer::new();
let mem = vec![1002,4,3,4,33];
mem.iter().for_each(|&n| computer.push(n));
println!{"{:?}", computer}
computer.compute();
println!{"{:?}", computer}
assert_eq!{99, computer.mem[4]}
}
#[test]
fn tc2() {
let mut computer = Computer::new();
let mem = vec![1101,100,-1,4,0];
mem.iter().for_each(|&n| computer.push(n));
println!{"{:?}", computer}
computer.compute();
println!{"{:?}", computer}
assert_eq!{99, computer.mem[4]}
}
}