Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
4d197c4a89 |
2 changed files with 448 additions and 1 deletions
|
@ -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"
|
443
src/day9/main.rs
Normal file
443
src/day9/main.rs
Normal file
|
@ -0,0 +1,443 @@
|
|||
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,
|
||||
}
|
||||
|
||||
// impl From<usize> for Var {
|
||||
// fn from(i: usize) -> Self {
|
||||
// match i {
|
||||
// 0 => Var::Opcode,
|
||||
// 1 => Var::A,
|
||||
// 2 => Var::B,
|
||||
// 3 => Var::C,
|
||||
// _ => panic!("invalid variable")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Into<usize> for Var {
|
||||
// fn into(self) -> usize {
|
||||
// match self {
|
||||
// Var::Opcode => 0,
|
||||
// Var::A => 1,
|
||||
// Var::B => 2,
|
||||
// Var::C => 3,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[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 x = *self.program.get(self.pos + *v as usize).unwrap_or(&0);
|
||||
match self.modes.mode_for(v) {
|
||||
Mode::Position => self.get_pos(x as usize),
|
||||
Mode::Immediate => x,
|
||||
Mode::Relative => self.get_pos((self.rel + x) as usize),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
Mode::Immediate => want as i64,
|
||||
Mode::Relative => self.get_pos((self.rel + want as i64) as usize),
|
||||
} as usize;
|
||||
if length < want {
|
||||
let missing = (want - length) + 2;
|
||||
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)?);
|
||||
let result = computer.clone_with_input(vec![1]).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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue