diff --git a/2016/input/day_23.txt b/2016/input/day_23.txt new file mode 100644 index 0000000..8484ab8 --- /dev/null +++ b/2016/input/day_23.txt @@ -0,0 +1,26 @@ +cpy a b +dec b +cpy a d +cpy 0 a +cpy b c +inc a +dec c +jnz c -2 +dec d +jnz d -5 +dec b +cpy b c +cpy c d +dec d +inc c +jnz d -2 +tgl c +cpy -16 c +jnz 1 c +cpy 94 c +jnz 82 d +inc a +inc d +jnz d -2 +inc c +jnz c -5 \ No newline at end of file diff --git a/2016/rust/src/assembunny.rs b/2016/rust/src/assembunny.rs index bf6d680..0b1f23a 100644 --- a/2016/rust/src/assembunny.rs +++ b/2016/rust/src/assembunny.rs @@ -1,3 +1,4 @@ +use std::fmt; use std::ops; use std::str; @@ -9,6 +10,10 @@ pub struct Assembunny { } impl Assembunny { + fn instruction(&self, i: usize) -> Option { + self.instructions.get(i).cloned() + } + fn value>(&self, v: V) -> isize { let v: Variable = v.into(); match v { @@ -16,6 +21,22 @@ impl Assembunny { Variable::Value(i) => i, } } + + fn toggle(&mut self, i: usize) { + let instruction = match self.instruction(i) { + Some(x) => x, + None => return, + }; + + let replacement = match instruction { + Instruction::Cpy(a, b) => Instruction::Jnz(a, b), + Instruction::Inc(x) => Instruction::Dec(x), + Instruction::Dec(x) => Instruction::Inc(x), + Instruction::Jnz(a, b) => Instruction::Cpy(a, b), + Instruction::Tgl(x) => Instruction::Inc(x), + }; + self.instructions[i] = replacement; + } } impl Iterator for Assembunny { @@ -23,41 +44,43 @@ impl Iterator for Assembunny { fn next(&mut self) -> Option { let pc = self.value(Register::PC) as usize; - let instruction = match self.instructions.0.get(pc) { + let instruction = match self.instruction(pc) { Some(i) => i, None => { return None; } }; - match *instruction { - Instruction::Cpy(v, r) => { + self.registers[Register::PC] += 1; + match instruction { + Instruction::Cpy(v, Variable::Register(r)) => { let value = self.value(v); self.registers[r] = value; - self.registers[Register::PC] += 1; } - Instruction::Inc(r) => { + Instruction::Inc(Variable::Register(r)) => { self.registers[r] += 1; - self.registers[Register::PC] += 1; } - Instruction::Dec(r) => { + Instruction::Dec(Variable::Register(r)) => { self.registers[r] -= 1; - self.registers[Register::PC] += 1; } - Instruction::Jnz(v, i) => { - let delta = if self.value(v) == 0 { 1 } else { i }; - let pc = self.value(Register::PC) + delta; + Instruction::Jnz(v, delta) if self.value(v) != 0 => { + let delta = self.value(delta); + let pc = self.value(Register::PC) + delta - 1; self.registers[Register::PC] = pc; } + Instruction::Tgl(v) => { + let index = (pc as isize) + self.value(v); + self.toggle(index as usize); + } + _ => {} } Some(self.registers.clone()) } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Registers(Vec); -pub struct Instructions(Vec); impl Registers { pub fn new() -> Self { @@ -88,6 +111,40 @@ impl ops::IndexMut for Registers { } } +pub struct Instructions(Vec); + +impl Instructions { + fn get(&self, i: usize) -> Option<&Instruction> { + self.0.get(i) + } +} + +impl fmt::Display for Instructions { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, + "{}", + self.0 + .iter() + .map(Instruction::to_string) + .collect::>() + .join("\n")) + } +} + +impl ops::Index for Instructions { + type Output = Instruction; + + fn index(&self, _index: usize) -> &Instruction { + self.0.index(_index) + } +} + +impl ops::IndexMut for Instructions { + fn index_mut(&mut self, _index: usize) -> &mut Instruction { + self.0.index_mut(_index) + } +} + #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] pub enum Register { PC, @@ -98,19 +155,43 @@ pub enum Register { } #[derive(Clone, Copy, Debug, PartialEq)] -enum Instruction { - Cpy(Variable, Register), - Inc(Register), - Dec(Register), - Jnz(Variable, isize), +pub enum Instruction { + Cpy(Variable, Variable), + Inc(Variable), + Dec(Variable), + Jnz(Variable, Variable), + Tgl(Variable), +} + +impl fmt::Display for Instruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Instruction::Cpy(a, b) => write!(f, "cpy {} {}", a, b), + &Instruction::Inc(a) => write!(f, "cpy {}", a), + &Instruction::Dec(a) => write!(f, "cpy {}", a), + &Instruction::Jnz(a, b) => write!(f, "cpy {} {}", a, b), + &Instruction::Tgl(a) => write!(f, "cpy {}", a), + } + } } #[derive(Clone, Copy, Debug, PartialEq)] -enum Variable { +pub enum Variable { Register(Register), Value(isize), } +impl fmt::Display for Variable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Variable::Register(r) => { + write!(f, "{}", format!("{:?}", r).to_lowercase()) + } + &Variable::Value(v) => write!(f, "{:?}", v), + } + } +} + impl From for Variable { fn from(r: Register) -> Self { Variable::Register(r) @@ -149,22 +230,26 @@ impl str::FromStr for Instruction { match tokens.next() { Some("cpy") => { let v = tokens.read_variable()?; - let r = tokens.read_register()?; + let r = tokens.read_variable()?; Ok(Instruction::Cpy(v, r)) } Some("inc") => { let r = tokens.read_register()?; - Ok(Instruction::Inc(r)) + Ok(Instruction::Inc(Variable::Register(r))) } Some("dec") => { let r = tokens.read_register()?; - Ok(Instruction::Dec(r)) + Ok(Instruction::Dec(Variable::Register(r))) } Some("jnz") => { let var = tokens.read_variable()?; - let val = tokens.read_value()?; + let val = tokens.read_variable()?; Ok(Instruction::Jnz(var, val)) } + Some("tgl") => { + let var = tokens.read_variable()?; + Ok(Instruction::Tgl(var)) + } Some(inst) => Err(format!("invalid instruction '{}'", inst).into()), None => Err("no instruction".into()), } @@ -210,7 +295,6 @@ impl<'a> SplitWhitespaceExt for str::SplitWhitespace<'a> { #[cfg(test)] mod tests { use super::*; - use super::{Instruction, Variable}; use std::str::FromStr; #[test] @@ -241,6 +325,52 @@ dec a" assert_eq!(registers[Register::PC], 6); } + #[test] + fn test_toggle_integration() { + let instructions: Instructions = "cpy 2 a +tgl a +tgl a +tgl a +cpy 1 a +dec a +dec a" + .parse() + .unwrap(); + + let assembunny = Assembunny { + registers: Registers::new(), + instructions: instructions, + }; + + let registers = assembunny.last().unwrap(); + assert_eq!(registers[Register::A], 3); + assert_eq!(registers[Register::PC], 7); + } + + #[test] + fn test_toggle() { + let instructions: Instructions = "tgl a" + .parse() + .unwrap(); + + let mut assembunny = Assembunny { + registers: Registers::new(), + instructions: instructions, + }; + + assembunny.toggle(0); + assert_eq!(assembunny.instruction(0), + Some(Instruction::Inc(Variable::Register(Register::A)))); + + assembunny.toggle(0); + assert_eq!(assembunny.instruction(0), + Some(Instruction::Dec(Variable::Register(Register::A)))); + + assembunny.toggle(0); + assert_eq!(assembunny.instruction(0), + Some(Instruction::Inc(Variable::Register(Register::A)))); + } + #[test] fn test_instructions_from_str() { let i: Instructions = "cpy 41 a @@ -262,12 +392,16 @@ dec a" assert!(Instruction::from_str("inc 5").is_err()); assert_eq!(Instruction::from_str("cpy 41 a").unwrap(), - Instruction::Cpy(Variable::Value(41), Register::A)); + Instruction::Cpy(Variable::Value(41), + Variable::Register(Register::A))); assert_eq!(Instruction::from_str("inc a").unwrap(), - Instruction::Inc(Register::A)); + Instruction::Inc(Variable::Register(Register::A))); assert_eq!(Instruction::from_str("dec b").unwrap(), - Instruction::Dec(Register::B)); + Instruction::Dec(Variable::Register(Register::B))); assert_eq!(Instruction::from_str("jnz c 2").unwrap(), - Instruction::Jnz(Variable::Register(Register::C), 2)); + Instruction::Jnz(Variable::Register(Register::C), + Variable::Value(2))); + assert_eq!(Instruction::from_str("tgl a").unwrap(), + Instruction::Tgl(Variable::Register(Register::A))); } } diff --git a/2016/rust/src/day_23.rs b/2016/rust/src/day_23.rs new file mode 100644 index 0000000..92e4626 --- /dev/null +++ b/2016/rust/src/day_23.rs @@ -0,0 +1,13 @@ +use assembunny::*; +use errors::*; + +pub fn solve(input: &str) -> Result { + let instructions: Instructions = input.parse()?; + let mut registers = Registers::new(); + registers[Register::A] = 7; + let assembunny = Assembunny{registers: registers, instructions: instructions}; + + let registers = assembunny.last().ok_or("")?; + let a = registers[Register::A]; + Ok(a.to_string()) +} diff --git a/2016/rust/src/lib.rs b/2016/rust/src/lib.rs index 1130314..ff55076 100644 --- a/2016/rust/src/lib.rs +++ b/2016/rust/src/lib.rs @@ -19,3 +19,4 @@ pub mod day_08; // pub mod day_09; // pub mod day_10; pub mod day_12; +pub mod day_23; diff --git a/2016/rust/src/main.rs b/2016/rust/src/main.rs index 27be66b..8eba962 100644 --- a/2016/rust/src/main.rs +++ b/2016/rust/src/main.rs @@ -10,7 +10,7 @@ fn main() { let mut input = String::new(); io::stdin().read_to_string(&mut input).ok(); - let solution = day_12::solve(&input)?; + let solution = day_23::solve(&input)?; println!("{}", solution); Ok(())