[2016][rust][23.0]
change vknplutyquzwksnssqvtzuknxrnxkspn
commit c8626051ff4ee157d0ccb4072cf221bbe9c4d942
author Alpha Chen <alpha.chen@gmail.com>
date
parent zokvvmot
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<Instruction> {
+        self.instructions.get(i).cloned()
+    }
+
     fn value<V: Into<Variable>>(&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<Registers> {
         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<isize>);
-pub struct Instructions(Vec<Instruction>);
 
 impl Registers {
     pub fn new() -> Self {
@@ -88,6 +111,40 @@ impl ops::IndexMut<Register> for Registers {
     }
 }
 
+pub struct Instructions(Vec<Instruction>);
+
+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::<Vec<_>>()
+                   .join("\n"))
+    }
+}
+
+impl ops::Index<usize> for Instructions {
+    type Output = Instruction;
+
+    fn index(&self, _index: usize) -> &Instruction {
+        self.0.index(_index)
+    }
+}
+
+impl ops::IndexMut<usize> 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<Register> 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<String> {
+    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(())