use std::io; use std::ops; use std::cmp; use std::io::prelude::*; /// Apply Erathostenes's sieve to the supplied array /// /// # Arguments /// /// * `dest` - the destination slice to fill with the sieve. This is /// assumed to be filled with "true" before being handed to this /// method. pub fn prime_sieve(dest: &mut[bool]) { if dest.len() >= 1 { dest[0] = false; } if dest.len() >= 2 { dest[1] = false; } let limit = (dest.len() as f64).sqrt() as usize; for i in 1..(limit + 1) { if !dest[i] { continue } for j in ((i * i)..(dest.len())).step_by(i) { dest[j] = false; } } } /// Greatest common divisor pub fn gcd + cmp::PartialOrd + std::convert::From + Copy>(a: T, b: T) -> T { if a < b { gcd(b, a) } else { if a % b == T::from(0) { b } else { gcd(a % b, b) } } } /// Least common multiple pub fn lcm + ops::Mul + ops::Div + cmp::PartialOrd + std::convert::From + Copy>(a: T, b: T) -> T { a * b / gcd(a, b) } /// Solution trait /// /// Every day's solution should implement this function so that it can /// be easily run from the main program. pub trait Solution { /// Solve the first part of the day fn part1(&mut self, input: &mut io::Read) -> String; /// Solve the second part of the day fn part2(&mut self, _input: &mut io::Read) -> String { panic!("Not implemented yet."); } } #[derive(Default)] pub struct AssemBunnyCPU { instructions: Vec>, pub registers: [i32; 4] } fn register_num(value: &str) -> Option { match value { "a" => Some(0), "b" => Some(1), "c" => Some(2), "d" => Some(3), _ => None, } } impl AssemBunnyCPU { fn get_value(&self, value: &str) -> i32 { match register_num(value) { Some(num) => self.registers[num], None => value.parse().unwrap() } } pub fn read_instructions(&mut self, input: &mut io::Read) { let reader = io::BufReader::new(input); for line in reader.lines() { let contents = line.unwrap(); let parts: Vec = contents.split(" ").map(|part| String::from(part)).collect(); self.instructions.push(parts); } } pub fn run(&mut self)-> i32 { let mut iptr: i32 = 0; while iptr < self.instructions.len() as i32 { let mut instruction_target = 0; let mut new_instruction = Vec::new(); { let ref instruction = self.instructions[iptr as usize]; match instruction[0].as_ref() { "cpy" => { let val = self.get_value(&instruction[1]); match register_num(&instruction[2]) { Some(num) => { self.registers[num] = val; }, None => { // Invalid instruction generated. }, } }, "jnz" => { let val = self.get_value(&instruction[1]); if val != 0 { let jump: i32 = self.get_value(&instruction[2]); iptr += jump; continue; } }, "inc" => { match register_num(&instruction[1]) { Some(num) => { self.registers[num] += 1 }, None => { // Invalid instruction generated. }, } }, "dec" => { match register_num(&instruction[1]) { Some(num) => { self.registers[num] -= 1; }, None => { // Invalid instruction generated. }, } }, "tgl" => { instruction_target = (iptr + self.get_value(&instruction[1])) as usize; if instruction_target < self.instructions.len() { new_instruction = self.instructions[instruction_target].clone(); new_instruction[0] = String::from(match new_instruction.len() { 2 => match new_instruction[0].as_str() { "inc" => "dec", _ => "inc", } 3 => match new_instruction[0].as_str() { "jnz" => "cpy", _ => "jnz", }, _ => panic!("Cannot toggle instruction {}", instruction_target), }); } }, _ => panic!("Invalid instruction: {:?}", instruction), } } iptr += 1; // Check if we need to override an instruction if new_instruction.len() != 0 { self.instructions[instruction_target] = new_instruction; } } self.get_value("a") } } #[cfg(test)] mod tests { use super::*; #[test] fn test_prime_sieve() { let mut input = [true; 10]; prime_sieve(&mut input); let output = [ false, false, true, true, false, true, false, true, false, false ]; assert_eq!(output, input); } #[test] fn test_gcd() { assert_eq!(12, gcd(24, 36)); assert_eq!(1, gcd(1, 7)); } #[test] fn test_lcm() { assert_eq!(12, lcm(6, 4)); } }