Files
adventofcode/2016/src/common.rs
2018-11-22 15:59:51 +01:00

208 lines
6.0 KiB
Rust

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<T: ops::Rem<Output = T> + cmp::PartialOrd + std::convert::From<i32> + 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<T: ops::Rem<Output = T> + ops::Mul<Output = T> + ops::Div<Output = T> + cmp::PartialOrd + std::convert::From<i32> + 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<Vec<String>>,
pub registers: [i32; 4]
}
fn register_num(value: &str) -> Option<usize>
{
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<String> = 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));
}
}