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(())